python 的之间有时需要通信,操作系统提供了很多机制来实现进程间的通信。
1. Queue的使用
multiprocessing模块的Queue如果用与Pool创建的进程,会报错
RuntimeError: Queue objects should only be shared between processes through inheritance.
看一个实例:
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
for value in ['A', 'B', 'C']:
print 'Put %s to queue...' % value
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
while True:
if not q.empty():
value = q.get(True)
print 'Get %s from queue.' % value
time.sleep(random.random())
else:
break
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 等待pw结束:
pw.join()
# 启动子进程pr,读取:
pr.start()
pr.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
print ''
print '所有数据都写入并且读完'
Manager().Queue()可以用与multiprocessing创建的进程和Pool创建的进程中.
下面的案例演示进程池(Pool)之间的通信
#coding=utf-8
#修改import中的Queue为Manager
from multiprocessing import Manager,Pool
import os,time,random
def reader(q):
print("reader启动(%s),父进程为(%s)"%(os.getpid(),os.getppid()))
for i in range(q.qsize()):
print("reader从Queue获取到消息:%s"%q.get(True))
def writer(q):
print("writer启动(%s),父进程为(%s)"%(os.getpid(),os.getppid()))
for i in ["A", "B", "C", "D"]:
q.put(i)
if __name__=="__main__":
print("(%s) start"%os.getpid())
q=Manager().Queue() #使用Manager中的Queue来初始化
po=Pool()
#使用阻塞模式创建进程,这样就不需要在reader中使用死循环了,可以让writer完全执行完成后,再用reader去读取
po.apply(writer,(q,))
po.apply(reader,(q,))
po.close()
po.join()
print("(%s) End"%os.getpid())
2. Pipe的使用
- Pipe常用于两个进程,两个进程分别位于管道的两端.
- Pipe方法返回(conn1,conn2)代表一个管道的两个端,Pipe方法有duplex参数,默认为True,即全双工模式,若为FALSE,conn1只负责接收信息,conn2负责发送,
- send和recv方法分别为发送和接收信息。
下面的案例演示如何使用Pipe
# coding:utf-8
import multiprocessing
import os,time,random
#写数据进程执行的代码
def proc_send(pipe):
#print 'Process is write....'
for url in ["A", "B", "C", "D"]:
print 'Process is send :%s' %url
pipe.send(url)
time.sleep(random.random())
#读数据进程的代码
def proc_recv(pipe):
while True:
print('Process rev:%s' %pipe.recv())
time.sleep(random.random())
if __name__ == '__main__':
#父进程创建pipe,并传给各个子进程
s_pipe, r_pipe = multiprocessing.Pipe()
p1 = multiprocessing.Process(target=proc_send,args=(s_pipe,))
p2 = multiprocessing.Process(target=proc_recv,args=(r_pipe,))
#启动子进程,写入
p1.start()
p2.start()
p1.join()
p2.terminate()
4. 多进程和全局变量
共享变量不适用于多进程,进程间的变量是互相隔离的,子进程的全局变量是完全复制一份父进程的数据,对子进程的全局变量修改完全影响不到其他进程的全局变量.
下面的案例演示的是多进程对全局变量的影响
def producer(a):
a += 1
time.sleep(2)
def consumer(a):
time.sleep(3)
data = a
print(data)
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
Process finished with exit code 0
总结:在多线程中,我们可以比较容易地共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过以上方法共享全局变量.实际我们也可以通过共享内存和Manager的方法来共享资源.有时间了再接着看其他方式.