以下多处理示例适用于我的Ubuntu计算机。它启动一个进程,通过队列发送参数,并通过另一个队列接收计算结果:
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import multiprocessing
import Queue
running = multiprocessing.Value('i', 1)
request = multiprocessing.Queue(1)
response = multiprocessing.Queue(1)
def worker():
while running.value:
try:
param = request.get(timeout=0.1)
except Queue.Empty:
# To check running flag.
continue
# Imagine heavy computation here.
result = param ** 2
response.put_nowait(result)
def main():
process = multiprocessing.Process(target=worker)
process.start()
request.put_nowait(42)
result = response.get()
print('Result', result)
running.value = 0
process.join()
if __name__ == '__main__':
main()
但是,网上的几个示例似乎通过multiprocessing.Process(target=worker, args=(running, request, response)
传递了工作人员所需的所有对象。这是否有必要出于任何原因,例如平台兼容性?
答案 0 :(得分:2)
人们倾向于遵循multiprocessing programming guidelines:
最好继承而不是pickle / unpickle
在Windows上,需要对多处理中的许多类型进行选择,以便子进程可以使用它们。但是,通常应避免使用管道或队列将共享对象发送到其他进程。相反,您应该安排程序,以便需要访问其他地方创建的共享资源的进程可以从祖先进程继承它。
如果您的实现足够简单,您可以使用全局变量。然而,在更复杂的情况下,您可能希望避免它们并且更喜欢更好的封装。
此外,由于操作系统处理creation of new processes的方式,您的实现很可能无法在Windows上运行。
Unix使用fork
复制父进程资源。因此,子进程继承了父打开的文件(在您的情况下为Queue
)。
Windows使用spawn
方法,而是创建一个"空白"进程,加载一个新的Python解释器,并尝试重新构造运行target
函数所需的最小值。新流程很可能会有一个与父流程不同的全新Queue
。因此,您将发送的数据永远不会到达子进程。
关于最后一条语句的注释:Python multiprocessing
库试图提供与OS无关的体验(我个人不喜欢)。这意味着由于这项工作,您的代码可能仍在Windows上运行。
由于fork和spawn之间的实际差异没有详细记录,因此始终建议遵循编程指南以避免出现奇怪的行为。