Python 高级编程和异步IO并发编程 --11_11 进程间通信

进程间也需要通信。进程间通信与线程间通信有相同的地方,也有不同的地方。

不同点:之前在多线程通信中,线程间同步的类,与线程间同步的锁在多进程中无法使用。

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}

发现,两个进程向公共空间写的东西,都被存储起来。

发布了309 篇原创文章 · 获赞 120 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/f2157120/article/details/105109589