python 锁
内容概要
- 进程对象及其他方法
- 僵尸进程与孤儿进程
- 守护进程
- 互斥锁
- 队列介绍
- 进程间通信IPC机制
- 生产者消费者模型
- 线程相关知识点
进程对象及其他方法
如何查看进程的PID号
命令法:
windows: tasklist
tasklist |findstr PID查看具体的进程
mac: 进入终端之后输入ps aux
ps aux|grep PID查看具体的进程
用python功能查看:
from multiprocessing import Process,current_process
pid = current_process().pid # 查看当前进程的进程号
p.terminate() # 杀死当前进程,是告诉操作系统帮你去杀死当前进程 但是需要一定的时间 而代码的运行速度极快
p.is_alive() # 判断当前进程是否存活
用OS模块的功能查看:
import os
os.getpid() # 查看当前进程进程号
os.getppid() # 查看当前进程的父进程进程号
代码实现:
from multiprocessing import Process,current_process
import os
import time
def task(name):
print(f'子进程{name}开始')
# pid_1 = current_process().pid
pid_1 = os.getpid()
pid_2 = os.getppid()
print(pid_1)
print(pid_2)
print(f'子进程运行{name}结束')
if __name__ == '__main__':
# pid = current_process().pid
pid = os.getpid()
print(pid,'主')
p = Process(target=task, args=('1',))
p.start()
time.sleep(3) # 不能刚运行就杀死该程序
p.terminate()
time.sleep(2)
print(p.is_alive())
僵尸进程与孤儿进程
# 僵尸进程
"""
死了但是没有死透
当你开设了子进程之后 该进程死后不会立刻释放占用的进程号
因为子进程要让父进程能够查看到它开设的子进程的一些基本信息 占用的pid号 运行时间
父进程会回收子进程占用的pid号等,父进程调用join方法等待子进程运行结束
所有的进程都会步入僵尸进程
危险的僵尸进程: 父进程不死并且在无限制的创建子进程并且子进程也不结束
"""
# 孤儿进程
"""
子进程存活,父进程意外死亡
操作系统会开设一个“儿童福利院”专门管理孤儿进程回收相关资源
"""
守护进程
该子进程与主进程同生死,只要主进程结束,该守护进程一定会立即终止
方法:
p.daemon = True
注意: 将进程p设置成守护进程 这一句一定要放在start方法上面才有效否则会直接报错
互斥锁
多个进程操作同一份数据的时候,会出现数据错乱的问题
针对上述问题,解决方式就是加锁处理:将并发变成串行,牺牲效率但是保证了数据的安全
用法:
调用锁类生成互斥对象
mutex = Lock()
获得该互斥对象
mutex.accquire()
释放该互斥对象
mutex.release()
扩展: 行锁 表锁
注意:
1.锁不能轻易的使用,容易造成死锁现象(我们写代码一般不会用到,都是内部封装好的)
2.锁只在处理数据的部分加来保证数据安全(只在争抢数据的环节加锁处理即可)
代码实现:
def run(i, mutex):
search(i)
# 给买票环节加锁处理
# 抢锁
mutex.acquire()
buy(i) # 操作数据
# 释放锁
mutex.release()
if __name__ == '__main__':
# 在主进程中生成一把锁 让所有的子进程抢 谁先抢到谁先买票
mutex = Lock()
for i in range(1,11):
p = Process(target=run, args=(i, mutex))
p.start()
队列介绍
队列:管道+锁
管道:subprocess
stdin stdout stderr
队列:先进先出
堆栈:先进后出
使用方法:
from multiprocessing import Queue
# 创建一个队列
q = Queue # 括号内可以传数字 标示生成的队列最大可以同时存放的数据量
# 往队列中存数据,当队列数据放满了之后 如果还有数据要放程序会阻塞 直到有位置让出来 不会报错
q.put('传的值')
# 去队列中取数据,队列中如果已经没有数据的话 get方法也会原地等待(阻塞)直到有数据为止
v = q.get()
v = q.get_nowait() # 没有数据直接报错,信息为:queue.Empty
v = q.get(timeout=3) # 没有数据之后原地等待三秒之后再报错,信息为: queue.Empty
其他方法:
q.full() # 判断当前队列是否满了
q.empty() # 判断当前队列是否空了
"""
q.full()
q.empty()
q.get_nowait()
在多进程的情况下是不精确,因为下一瞬间队列可能被其他进程操作了
"""
代码实现:
from multiprocessing import Queue
q = Queue(3)
q.put(1)
q.put(2)
q.put(3)
try:
print(q.full())
v_1 = q.get()
print(v_1)
v_2 = q.get()
print(v_2)
v_3 = q.get()
print(v_3)
print(q.empty())
v_4 = q.get(timeout=3)
print(v_4)
except Exception as e:
print('没有数据了')
IPC机制
进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。
这里借助队列通信
使用方法:
同上
代码实现:
from multiprocessing import Queue,Process
def producer(q):
q.put('hello')
if __name__ == '__main__':
q = Queue()
p = Process(target=(producer), args=(q,))
p.start()
res = q.get()
print(res)
生产者消费者模型
生产者:生产/制造东西的
消费者:消费/处理东西的
该模型除了上述两个之外还需要一个媒介就是 队列
核心思想:
调用JoinableQueue模块用来计数,将消费者设置成守护进程,当q.join()运行时代表队列的数据已全部被消化,此时关闭主进程.
该模块功能:每当你往该队列中存入数据的时候 内部会有一个计数器+1,当你调用task_done的时候 计数器-1
q.join() 当计数器为0的时候 才往后运行
代码实现:
from multiprocessing import JoinableQueue,Process
import random
import time
def producer(x,porducer_name,q,name):
for i in range(x):
time.sleep(random.randint(1,3))
q.put(name)
print(f'{porducer_name}产生数据{name}')
def consumer(q,teacher_name):
while True:
time.sleep(random.randint(1,3))
name=q.get()
if name:
print(f'{teacher_name}处理数据{name}')
q.task_done()
if __name__ == '__main__':
q = JoinableQueue()
p2 = Process(target=producer,args=(4,'egon',q,'date'))
p3 = Process(target=producer,args=(4,'tank',q,'数据'))
p1 = Process(target=consumer, args=(q,'json'))
p4 = Process(target=consumer, args=(q,'lili'))
p2.start()
p3.start()
p1.daemon = True
p4.daemon = True
p4.start()
p1.start()
p2.join() # 如果不等这两个产生者,此时队列里没有数据,守护进程直接被干死了
p3.join() # 如果不等这两个产生者,此时队列里没有数据,守护进程直接被干死了
q.join()