进程间也需要通信。进程间通信与线程间通信有相同的地方,也有不同的地方。
不同点:之前在多线程通信中,线程间同步的类,与线程间同步的锁在多进程中无法使用。
1. 多线程中的Queue,在多进程编程中,已经不再可用
from multiprocessing import Process
from queue import Queue
import time
def producer(queue):
queue.put("a")
time.sleep(2)
def consumer(queue):
time.sleep(2)
data = queue.get()
print(data)
if __name__=="__main__":
queue = Queue(10)
my_producer = Process(target=producer,args=(queue,))
my_consumer = Process(target=consumer,args=(queue,))
my_producer.start()
my_consumer.start()
my_producer.join()
my_consumer.join()
Traceback (most recent call last):
File "C:/Users/Amber/PycharmProjects/test0/Chapter11/process_communication.py", line 18, in <module>
my_producer.start()
File "C:\Users\Amber\Anaconda3\lib\multiprocessing\process.py", line 112, in start
self._popen = self._Popen(self)
File "C:\Users\Amber\Anaconda3\lib\multiprocessing\context.py", line 223, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "C:\Users\Amber\Anaconda3\lib\multiprocessing\context.py", line 322, in _Popen
return Popen(process_obj)
File "C:\Users\Amber\Anaconda3\lib\multiprocessing\popen_spawn_win32.py", line 89, in __init__
reduction.dump(process_obj, to_child)
File "C:\Users\Amber\Anaconda3\lib\multiprocessing\reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
TypeError: can't pickle _thread.lock objects
发现执行报异常,说明在多线程中的Queue,在多进程编程中,已经不再可用。只需导入多进程专用Queue,其它代码不变,就可以执行。
from multiprocessing import Process,Queue
# from queue import Queue
import time
def producer(queue):
queue.put("a")
time.sleep(2)
def consumer(queue):
time.sleep(2)
data = queue.get()
print(data)
if __name__=="__main__":
queue = Queue(10)
my_producer = Process(target=producer,args=(queue,))
my_consumer = Process(target=consumer,args=(queue,))
my_producer.start()
my_consumer.start()
my_producer.join()
my_consumer.join()
a
2. 共享全局变量通信不适用于多进程
from multiprocessing import Process,Queue
import time
def producer(a):
a += 1
time.sleep(2)
def consumer(a):
time.sleep(2)
print(a)
if __name__=="__main__":
a = 1
my_producer = Process(target=producer,args=(a,))
my_consumer = Process(target=consumer,args=(a,))
my_producer.start()
my_consumer.start()
my_producer.join()
my_consumer.join()
1
上述代码,全局变量a=1,如果调用producer后,a+=1,consumer输出应该是2,可是结果仍然为1.因此此处共享全局变量在多进程中不适用。
3 Multiprocessing中的queue不能用于pool进程池
from multiprocessing import Process,Queue,Pool
import time
def producer(queue):
queue.put("a")
time.sleep(2)
def consumer(queue):
time.sleep(2)
data = queue.get()
print(data)
if __name__=="__main__":
queue = Queue(10)
pool = Pool(2)
pool.apply_async(producer,args=(queue,))
pool.apply_async(consumer,args=(queue,))
pool.close() # 停止接收新任务
pool.join() # 等待完成
执行发现没有输出,说明多进程中的queue,不可用于进程池中的进程间通信。
如何通信?需要导入多进程中的Manager,Manager可用实例化对象,
pool中的进程间通信需要使用Manager中的queue。
from multiprocessing import Process,Queue,Pool,Manager
import time
def producer(queue):
queue.put("a")
time.sleep(2)
def consumer(queue):
time.sleep(2)
data = queue.get()
print(data)
if __name__=="__main__":
queue = Manager().Queue(10) # 通过mamager实例化对象,mamager里面的Queue就可用实现进程间通信
pool = Pool(2)
pool.apply_async(producer,args=(queue,))
pool.apply_async(consumer,args=(queue,))
pool.close() # 停止接收新任务
pool.join() # 等待完成
a
4. Pipe实现进程间通信
from multiprocessing import Process,Pipe
import time
def producer(pipe):
pipe.send("a")
def consumer(pipe):
print(pipe.recv())
if __name__=="__main__":
receive_pipe,send_pipe = Pipe()
# pipe 只能适用于两个进程间通信。
my_producer = Process(target=producer,args=(send_pipe,))
my_consumer = Process(target=consumer,args=(receive_pipe,))
my_producer.start()
my_consumer.start()
my_producer.join()
my_consumer.join()
a
Pipe是简化版的Queue,其性能优于Queue,
Queue由于进程间通信加了很多锁,在特殊场合,如只用两个进程,优先考虑进程。
5. 通过Manager实现进程间共享内存操作
from multiprocessing import Process,Manager
def add_data(p_dict,key,value):
p_dict[key] = value
if __name__=="__main__":
progress_dict = Manager().dict()
first_progress = Process(target=add_data,args=(progress_dict,"Tom-1",18))
second_progress = Process(target=add_data,args=(progress_dict,"Tom-2",19))
first_progress.start()
second_progress.start()
first_progress.join()
second_progress.join()
print(progress_dict)
{'Tom-1': 18, 'Tom-2': 19}
发现,两个进程向公共空间写的东西,都被存储起来。