1. Manager可以提供进程之间共享的数据类型(list dict等)
先撇开进程,单纯看一下使用Manager创建一个dict的例子(只不过使用Manager创建的dict,进程之间都可以使用)
from multiprocessing import Manager from multiprocessing import Process if __name__=="__main__": m=Manager() # 实例化一个Manage对象 d=m.dict({"count":100}) # 使用Manager创建一个dict只不过这个字典可以在进程之间共享数据 d["name"]="xuanxuan" print(d)
运行结果:
2. 使用Manager创建进程之间共享的dict:
from multiprocessing import Manager from multiprocessing import Process import random import time def func(d): # 子进程执行的函数 print(d) d["count"]-=1 # 如果Manager创建的dict可以在进程之间共享数据,那么开多个进程执行func函数,字典的count每次都会减一操作 time.sleep(random.random()) if __name__=="__main__": m=Manager() # 实例化一个Manager对象 d=m.dict({"count":10}) # 使用Manager对象m创建了一个进程之间可以共享数据的字典d,并初始化未{"count":10} for i in range(10): p=Process(target=func,args=(d,)) p.start() p.join() # 判断进程是否结束,只有该子进程结束,才开下一个子进程(这样就变为同步的了) ,必须要加上这一句,否则打印出来的不对 d["name"] = "xuanxuan" # 第一个进程执行完之后,给d增加键值对,其他进程会接受到
运行结果:
(注意这里打印的是开启进程打印本次减之前的count值,第一个进程打印的10 接下来减一,,,最后开10个进程,最终得到的d count应该减10次变为0的,这里count=1是第十次减之前的,打印完之后才进行减一操作)
3. 使用Manager创建的进程之间共享的dict,异步实现进程之间通信:
from multiprocessing import Manager from multiprocessing import Process import time import random def func(d): # print(d) d["count"]-=1 time.sleep(random.random()) if __name__=="__main__": m=Manager() d=m.dict({"count":10}) P=[] # 存放开启的进程 for i in range(10): p=Process(target=func,args=(d,)) p.start() # p.join() # 判断该子进程是否结束,结束了才会继续开下一个进程(所以这样就会变成同步的) P.append(p) # 把开启的进程放在列表中 [p.join() for p in P] # 把刚才开的10个进程放在列表,该语句执行代表开的10个进程全部结束 print(d) # 实现异步,就不再是开一个结束一个,再开下一个进程这样的同步过程,所有进程全都打开,然后一起判断结束,就是西安了异步
运行结果:
正常情况下开启10个子进程,减10次得到的应该是0,但是这里异步实现之后,得到的count变为1 说明好像少减了一次,其实是两个进程在同一时间操作func中的字典d数据,两者同时进行减一操作,减完了放回去,但是效果其实就是减了一次(比如两个进程同时拿到的count为7 都进行减一操作,都把count变为6,都放回去,所以表面上看 ,这两个进程相当于只进行了一次减一操作)
这就造成了数据的不安全,所以使用Manager创建的进程之间共享数据的dict是不安全的,有可能多个进程同时操作数据,所以应该加锁:
from multiprocessing import Process from multiprocessing import Manager from multiprocessing import Lock import random import time def func(d,lock): # 子进程执行该函数,但是每一个子进程拿到之后会先拿一把钥匙,占用资源,其他进程只能等待该进程执行完毕,释放钥匙,这就保证了开多个进程数据安全 lock.acquire() # 进程加锁,进程执行到func先获得锁,使得同一时间只有一个进程可以操作func,等进程执行完d["count"]-=1 再释放锁 d["count"]-=1 time.sleep(random.random()) lock.release() if __name__=="__main__": m=Manager() d=m.dict({"count":10}) lock=Lock() P=[] # 存放开的进程,等到所有进程都结束,而不是开一个进程,判断结束,再开下一个进程造成的同步,一下开很多进程,最后一起判断结束这样可以实现异步 for i in range(10): p=Process(target=func,args=(d,lock)) p.start() P.append(p) [p.join() for p in P] # 开的多个进程,一起判断进程是否结束(这里一定要判断进程是否结束,否则会报错,不知道为什么Eva-) print(d) # 加了锁之后,这样数据就安全了,同一时间只有一个进程可以操作func,所以不会出现两个进程同时操作dict的count的情况,加锁之后得到的d["count"]一定是0
运行结果: