进程之间有时候需要通信,可以使用 multiprocessing 模块中的 Queue 类来实现进程间的数据传递,Queue 是一个消息队列,循序 先进先出 的规则;
初始化 Queue 对象时(q = Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限,直到内存的尽头;
Queue 常用的方法:
- Queue.qsize():返回当前消息队列包含的消息数量;
- Queue.empty():如果队列为空,返回 True,否则返回 False;
- Queue.full():如果队列满了,返回 True,否则返回 False;
- Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从队列中移除,block 默认值为 True;
(1)、如果 block 使用默认值(True),并且没有设置 timeout(单位秒),这种情况下如果消息队列为空,程序将被阻塞(停在读取状态),直到从消息队列读到消息为止;如果设置了 timeout,则会等待 timeout 秒,若还没有读取到任何消息,则抛出 "Queue.Empty" 异常;
(2)、如果 block 值为 False,并且消息队列为空,则会立刻抛出 "Queue.Empty" 异常; - Queue.get_nowait():相当于 Queue.get(False);
- Queue.put(item, [block[, timeout]]):将 item 消息写入队列,block 默认值为 True;
(1)、如果 block 使用默认值(True),并且没有指定 timeout,此时如果消息队列已满,程序将被阻塞(停在写入状态),直到从消息队列腾出空间为止;如果设置了 timeout,则会等待 timeout 秒,若还没有空间,则抛出 "Queue.full" 异常;
(2)、如果 block 值为 False,并且消息队列已满,则会立刻抛出 "Queue.full" 异常; - Queue.put_nowait(item):相当于 Queue.put(item, False);
下面例子用于演示 Queue 的工作原理:
# 导入 multiprocessing 模块中的 Queue
from multiprocessing import Queue
# 初始化一个 Queue 对象,最多可以储存 3 个消息
queue = Queue(3)
print(queue.empty()) # True:表示消息队列是空的
# 向队列中添加消息
queue.put("消息1")
queue.put("消息2")
print(queue.full()) # False:表示消息队列未满
queue.put("消息3")
print(queue.full()) # True:表示消息队列已满
# 获取消息队列中的消息数量
print("队列中的消息数量:", queue.qsize())
try:
# 如果消息队列已满,再向消息队列中添加消息时,会等待;
# 如果 block 为 True,则等待指定的秒数,直到等待时间结束,
# 如果消息队列还是满的,则会抛出 "Queue.full" 异常;
queue.put("消息4", True, 2)
except:
print("向消息队列中添加消息异常")
try:
# 消息队列已满,再向消息队列中添加消息时会立刻抛出异常;
# 相当于 queue.put("消息4", False)
queue.put_nowait("消息4")
# queue.put("消息4", False)
except:
print("向消息队列中添加消息失败")
# 推荐的方式:先判断消息队列是否已满,再写入
if not queue.full():
queue.put_nowait("消息4")
else:
print("消息队列已满")
# 先判断消息队列是否为空,再读取
if not queue.empty():
# 获取队列中的一条消息,然后将其从队列中移除
print(queue.get())
print("剩余消息数量:", queue.qsize())
print(queue.get())
print("剩余消息数量:", queue.qsize())
下面例子用于演示两个进程间的通信:一个进程向消息队列中写入数据,另一个进程从消息队列中读取数据:
# 导入 multiprocessing 模块中的 Process 和 Queue
from multiprocessing import Process, Queue
import time
# 向消息队列中写入数据
def write(queue):
# 循环从列表中取出数据写入到队列中
for value in ["how", "are", "you"]:
print("put %s to queue" %value)
queue.put(value)
time.sleep(1)
# 从消息队列中读取数据
def read(queue):
while True:
# 如果队列不为空,则从队列中读取数据
if not queue.empty():
print("get %s from queue" %(queue.get()))
time.sleep(1)
# 如果队列为空,则退出循环
else:
break
if __name__ == "__main__":
# 主进程中创建 queue 对象,传给各个子进程
queue = Queue()
# 创建子进程,执行写操作
pWrite = Process(target=write, args=(queue, ))
# 创建子进程,执行读操作
pRead = Process(target=read, args=(queue, ))
pWrite.start() # 启动子进程,开始写操作
pWrite.join() # 等待写操作执行结束,再继续向下执行
pRead.start() # 启动子进程,开始读操作
pRead.join() # 等待读操作执行结束,再继续向下执行
进程池中的 Queue:
上面使用的 multiprocessing.Queue 只能用于通过 Process 创建的子进程之间进行通信;
如果是通过进程池 Pool 方式创建的子进程间,就需要使用 multiprocessing.Manager.Queue 进行通信;
# 导入 multiprocessing 模块中的 Manager 和 Pool
from multiprocessing import Manager, Pool
import time
# 向消息队列中写入数据
def write(queue):
# 循环从列表中取出数据写入到队列中
for value in ["how", "are", "you"]:
print("put %s to queue" %value)
queue.put(value)
time.sleep(1)
# 从消息队列中读取数据
def read(queue):
# 根据队列中消息的数量循环读取消息
for i in range(queue.qsize()):
print("get %s from queue" %(queue.get()))
time.sleep(1)
if __name__ == "__main__":
# 主进程中创建 queue 对象,传给各个子进程
# 不能直接使用 queue = Queue() 创建对象;
queue = Manager().Queue()
# 创建进程池对象
pool = Pool()
# 以阻塞方式启动进程池中的子进程,执行写操作
pool.apply(write, (queue, ))
# 以阻塞方式启动进程池中的子进程,执行读操作
pool.apply(read, (queue, ))
pool.close() # 关闭进程池,不再接受新的请求
pool.join() # 等待进程池中所有子进程执行完毕