一、互斥锁
进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理。
注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行的修改,没错,速度是慢了,牺牲了速度而保证了数据安全。
1.上厕所的小例子:你上厕所的时候肯定得锁门吧,有人来了看见门锁着,就会在外面等着,等你吧门开开出来的时候,下一个人才去上厕所。
from multiprocessing import Process,Lock import os import time def work(mutex): mutex.acquire() print(‘task[%s] 上厕所‘%os.getpid()) time.sleep(3) print(‘task[%s] 上完厕所‘%os.getpid()) mutex.release() if __name__ == ‘__main__‘: mutex = Lock() p1 = Process(target=work,args=(mutex,)) p2 = Process(target=work,args=(mutex,)) p3 = Process(target=work,args=(mutex,)) p1.start() p2.start() p3.start() p1.join() p2.join() p3.join() print(‘主‘)
2.模拟抢票(也是利用了互斥锁的原理 :LOCK互斥锁)
import json import time import random import os from multiprocessing import Process,Lock def chakan(): dic = json.load(open(‘piao‘,)) # 先查看票数,也就是打开那个文件 print(‘剩余票数:%s‘ % dic[‘count‘]) # 查看剩余的票数 def buy(): dic = json.load(open(‘piao‘,)) if dic[‘count‘]>0: #如果还有票 dic[‘count‘]-=1 #就修改里面的值-1 time.sleep(random.randint(1,3)) #执行里面买票的一系列操作就先不执行了,让睡一会代替(并且随机的睡) json.dump(dic,open(‘piao‘,‘w‘)) print(‘%s 购票成功‘ % os.getpid()) # 当前的那个id购票成功 def task(mutex): #抢票 chakan() #因为查看的时候大家都可以看到,不需要加锁 mutex.acquire() #加锁 buy() #买的时候必须一个一个的买,先等一个人买完了,后面的人在买 mutex.release() #取消锁 if __name__ == ‘__main__‘: mutex = Lock() for i in range(50):#让50个人去访问那个票数 p = Process(target=task,args=(mutex,)) p.start()
二、Process对象的其他属性
p.daemon :守护进程(必须在开启之前设置守护进程):如果父进程死,子进程p也死了
p.join:父进程等p执行完了才运行主进程,是父进程阻塞在原地,而p仍然在后台运行。
terminate:强制关闭。(确保p里面没有其他子进程的时候关闭,如果里面有子进程,你去用这个方法强制关闭了就会产生僵尸进程(打个比方:如果你老子挂了,你还没挂,那么就没人给你收尸了,啊哈哈))
is_alive:关闭进程的时候,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
p.join():父进程在等p的结束,是父进程阻塞在原地,而p仍然在后台运行
p.name:查看名字
p.pid :查看id
我们可以简单介绍一下僵尸进程:
子进程运行完成,但是父进程迟迟没有进行回收,此时子进程实际上并没有退出,其仍然占用着系统资源,这样的?进程称为僵尸进程。
因为僵尸进程的资源一直未被回收,造成了系统资源的浪费,过多的僵尸进程将造成系统性能下降,所以应避免出现僵尸进程。
from multiprocessing import Process import os import time def work(): print(‘%s is working‘%os.getpid()) time.sleep(3) if __name__ == ‘__main__‘: p1 =Process(target=work) p2 =Process(target=work) p3 =Process(target=work) # p1.daemon = True # p2.daemon = True #守护进程(守护他爹) # p3.daemon = True #主进程死了子进程也死了(就不会执行子进程了) p1.start() p2.start() p3.start() p3.join() p2.join() p1.join() #多个join就是在等花费时间最长的那个运行完就执行主程序了 print(‘主程序‘) # -了解方法--------------- # p1.terminate() #强制关闭进程 # time.sleep(3) # print(p1.is_alive()) #看是不是还活着 # print(p1.name) #查看进程名字 # print(p1.pid) #查看id号 # print(‘主程序‘)
三、进程间的三种通信(IPC)方式:
方式一:队列(推荐使用)
进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的
1.队列:队列类似于一条管道,元素先进先出需要注意的一点是:队列都是在内存中操作,进程退出,队列清空,另外,队列也是一个阻塞的形态2.队列分类队列有很多种,但都依赖与模块queuequeue.Queue() #先进先出queue.LifoQueue() #后进先出queue.PriorityQueue() #优先级队列queue.deque() #双线队列
创建队列的类(底层就是以管道和锁定的方式实现):
Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列, 可以使用Queue实现多进程之间的数据传递。
参数介绍:
maxsize是队列中允许最大项数,省略则无大小限制。
方法介绍:
q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。 q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常. q.get_nowait():同q.get(False) q.put_nowait():同q.put(False) q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。 q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。 q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样
应用:
#队列 # 1.可以往队列里放任意类型的 # 2.先进先出 from multiprocessing import Process,Queue q= Queue(3) q.put(‘first‘) #默认block=True q.put(‘second‘) q.put(‘third‘) print(q.get()) print(q.get()) print(q.get())
原文地址:https://www.cnblogs.com/xiaohema/p/8454179.html