请参见下面的示例和执行结果:
#!/usr/bin/env python3.4
from multiprocessing import Pool
import time
import os
def initializer():
print("In initializer pid is {} ppid is {}".format(os.getpid(),os.getppid()))
def f(x):
print("In f pid is {} ppid is {}".format(os.getpid(),os.getppid()))
return x*x
if __name__ == '__main__':
print("In main pid is {} ppid is {}".format(os.getpid(), os.getppid()))
with Pool(processes=4, initializer=initializer) as pool: # start 4 worker processes
result = pool.apply(f, (10,)) # evaluate "f(10)" in a single process
print(result)
#result = pool.apply_async(f, (10,)) # evaluate "f(10)" in a single process
#print(result.get())
礼物:
$ ./pooleg.py
In main pid is 22783 ppid is 19542
In initializer pid is 22784 ppid is 22783
In initializer pid is 22785 ppid is 22783
In initializer pid is 22787 ppid is 22783
In f pid is 22784 ppid is 22783
In initializer pid is 22786 ppid is 22783
100
从输出中可以清楚地看到:创建了4个流程,但实际上只有其中一个完成了工作(称为f
)。
问题:为什么当工作apply()
仅由一个进程完成时,为什么我要创建一个由1个以上的工作人员组成的池并调用f
?对于apply_async()
也是一样,因为在这种情况下,工作也只能由一名工人完成。
我不了解这些功能有用的用例。
答案 0 :(得分:1)
代码中的这一行:
Pool(processes=4, initializer=initializer) as pool: # start 4 worker processes
没有启动 4个工作进程。它只是创建了一个池,无法支持同时运行多个池。像apply()
这样的方法实际上启动了单独运行的进程。
区别在于apply()
和apply_async()
的区别在于前者阻塞直到结果准备好,而后者立即返回“结果”对象。除非您一次要向Pool
提交多个任务(这当然是使用multiprocessing
模块的全部目的),否则这并没有多大区别。
这是对代码的一些修改,显示了如何实际使用Pool
进行一些并发处理:
from multiprocessing import Pool
import time
import os
def initializer():
print("In initializer pid is {} ppid is {}".format(os.getpid(),os.getppid()))
def f(x):
print("In f pid is {} ppid is {}".format(os.getpid(),os.getppid()))
return x*x
if __name__ == '__main__':
print("In main pid is {} ppid is {}".format(os.getpid(), os.getppid()))
with Pool(processes=4, initializer=initializer) as pool: # Create 4 worker Pool.
# result = pool.apply(f, (10,)) # evaluate "f(10)" in a single process
# print(result)
# Start multiple tasks.
tasks = [pool.apply_async(f, (val,)) for val in range(10, 20)]
pool.close() # No more tasks.
pool.join() # Wait for all tasks to finish.
results = [result.get() for result in tasks] # Get the result of each.
print(results)
map_sync()
更适合处理这样的(一系列值),因为它将自动处理上面代码中显示的一些细节。
答案 1 :(得分:1)
首先,两者都旨在对自变量元组(单个函数调用)进行操作,这与对可迭代对象进行操作的Pool.map
变体相反。因此,当您仅观察一次调用这些函数的过程时,这并不是一个错误。
您将使用Pool.apply_async
而不是Pool.map
版本之一,在该版本中,您需要对要分发的单个任务进行更精细的控制。
Pool.map
版本具有可迭代性,并将它们分块到任务中,其中每个任务具有 same (映射)目标功能。
Pool.apply_async
通常不会被超过1个工作人员调用一次。由于它是异步的,因此您可以遍历手动预捆绑的任务并将其提交给多个任务。
工人进程尚未完成之前。您的任务列表可以包含不同的目标功能,就像您在答案here中看到的那样。它还可以为this示例中的结果和错误注册回调。
这些属性使Pool.apply_async
用途广泛,并且是解决Pool.map
版本之一无法解决的unusual问题场景的首选工具。
Pool.apply
确实一见钟情(第二眼)并没有广泛使用。在以下情况下,您可以使用它来同步控制流:首先使用apply_async
启动多个任务,然后执行必须完成的任务,然后再使用apply_async
启动另一轮任务。
使用Pool.apply
可能还意味着当您已经有一个正在空闲的池时,让您为中间任务创建一个额外的流程。