[python] 多进程通信

引言

进程间通信与线程间通信有相同的地方,也有不同的地方。threading模块中用于线程同步的机制在进程中是不能够使用的,queue模块中的Queue类也是不能用的。举个例子:

from multiprocessing import Process
import time
from queue import Queue

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()
# 执行结果
# TypeError: can't pickle _thread.lock objects

可以看出,运行是报错了,虽然不能使用queue模块,但是multiprocessing模块提供了其他的方法。

进程通信

Queue

multiprocessing模块提供了适合进程通信的Queue类,用法和queue模块中的Queue一模一样,只是导入的包不一样。

from multiprocessing import Process, 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()

值得注意的是:对于multiprocessing模块中提供的进程池Pool类,Queue是不支持的!

Manager

multiprocessing模块中的Manager类也可用于进程同步且,更为强大,将其实例化之后,其中也存在Queue,用法相同,并且可以用于multiprocessing模块中提供的进程池Pool类。

除此之外,Manager里面提供了listdictValueSemaphoreLockCondition等用于进程同步的机制。举个dict的例子:

from multiprocessing import Process
from multiprocessing import 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,'key1','10'))
    second_progress = Process(target=add_data, args=(progress_dict,'key2','11'))
    first_progress.start()
    second_progress.start()
    first_progress.join()
    second_progress.join()

    print(progress_dict)
# 执行结果
# {'key1': '10', 'key2': '11'}

可以看到,两个进程同时操作同一个变量,确实都成功了。如果讲Manager().dict()换成普通的dict(),结果打印出来一定是空字典。

Pipe

pipe是简化办的Queue,只能用于两个进程之间通信,不适用于多个,优点是速度相对于Queue更快。

from multiprocessing import Process, Pipe
import time

def producer(pipe):
    pipe.send('send to you')
    time.sleep(2)
    data = pipe.recv()
    print('In producer recv:', data)


def consumer(pipe):
    time.sleep(2)
    data = pipe.recv()
    print('In consumer recv:',data)
    pipe.send('I recv')

if __name__ == "__main__":
    receive_pipe, send_pipe = Pipe()
    my_producer = Process(target=producer, args=(receive_pipe,))
    my_consumer = Process(target=consumer, args=(send_pipe,))
    my_producer.start()
    my_consumer.start()
    my_producer.join()
    my_consumer.join()
# 执行结果
# In consumer recv: send to you
# In producer recv: I recv

Pipe管道构建的时候返回两个对象,这两个对象之间可以通过sendrecv方法传递数据。

总结

  • 进程通信有Queue、Manager和Pipe三种方法。

参考

Python3高级编程和异步IO并发编程

你可能感兴趣的:([python] 多进程通信)