一、引入
展望未来,基于消息传递的并发编程是大势所趋;即便是使用线程,推荐做法也是将程序设计为大量独立的线程集合。通过消息队列交换数据。这样极大地减少了对使用锁定和其他同步手段的需求,还可以扩展到分布式系统中。
进程间应该尽量避免通信,即便需要通信,也应该选择进程安全的工具来避免加锁带来的问题,应该尽量避免使用本节所讲的共享数据的方式,以后我们会尝试使用数据库来解决进程之间的数据共享问题。
二、Manager模块 - 实现数据共享
1、定义
进程间数据是独立的,可以借助于队列或管道实现通信,二者都是基于消息传递的;虽然进程间数据独立,但可以通过Manager实现数据共享,事实上Manager的功能远不止于此。
多进程共同去处理共享数据的时候,就和我们多进程同时去操作一个文件中的数据是一样的,不加锁就会出现错误的结果,进程不安全的,所以也需要加锁
1 A manager object returned by Manager() controls a server process which holds Python objects and allows other processes to manipulate them using proxies. 2 3 A manager returned by Manager() will support types list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array.
1 from multiprocessing import Process,Manager 2 3 def func(m_dic): 4 m_dic['name'] = 'alex_luffy' # 子进程对数据进行了修改 5 6 if __name__ == '__main__': 7 m = Manager() 8 m_dic = m.dict({'name':'alex'}) 9 print('主进程', m_dic) # 先记录一下原始数据是啥样的 10 p = Process(target=func,args=(m_dic,)) # 将字典数据传递给子进程 11 p.start() 12 p.join() # 先让子进程执行完毕 13 14 print('主进程',m_dic) 15 结果: 16 主进程 {'name': 'alex'} 17 主进程 {'name': 'alex_luffy'} - m_dic内的数据被子进程修改了
2、创建多进程取修改子进程的数据(会出现数据不安全->会导致数据混乱加锁解决)
1 # 设置一个100数字,创建20个进程,分别去减一 2 3 from multiprocessing import Process,Manager,Lock 4 5 def func(m_dic,ml): 6 #不加锁的情况会出现数据错乱 7 # m_dic['count'] -= 1 8 9 #加锁,这是另外一种加锁形式 10 with ml: 11 m_dic['count'] -= 1 12 13 #等同 14 # ml.acquire() 15 # m_dic['count'] -= 1 16 # ml.release() 17 18 if __name__ == '__main__': 19 m = Manager() 20 ml = Lock() 21 m_dic = m.dict({'count':100}) 22 # print('主进程', m_dic) 23 p_list = [] 24 25 #开启20个进程来对共享数据进行修改 26 for i in range(20): 27 p1 = Process(target=func,args=(m_dic,ml,)) 28 p1.start() 29 p_list.append(p1) 30 [ppp.join() for ppp in p_list] 31 32 print('主进程',m_dic)
3、总结
下面要讲的信号量和事件也相当于锁,也是全局的,所有进程都能拿到这些锁的状态,进程之间这些锁啊信号量啊事件啊等等的通信,其实底层还是socekt,只不过是基于文件的socket通信,而不是跟上面的数据共享啊空间共享啊之类的机制,我们之前学的是基于网络的socket通信,还记得socket的两个家族吗,一个文件的一个网络的,所以将来如果说这些锁之类的报错,可能你看到的就是类似于socket的错误,简单知道一下就可以啦~~~