引言
进程间通信与线程间通信有相同的地方,也有不同的地方。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
里面提供了list
、dict
、Value
、Semaphore
、Lock
、Condition
等用于进程同步的机制。举个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
管道构建的时候返回两个对象,这两个对象之间可以通过send
和recv
方法传递数据。
总结
- 进程通信有Queue、Manager和Pipe三种方法。
参考
Python3高级编程和异步IO并发编程