我正在multiprocessing
尝试使用python
模块。我有以下示例代码,它在ipython笔记本中没有任何错误地执行。但我发现在后台生成了额外的python进程,每次执行代码块都在笔记本中。
import multiprocessing as mp
def f(x):
print "Hello World ", mp.current_process()
return 1
pool = mp.Pool(3)
data = range(0,10)
pool.map(f, data)
然而,当我在正常的.py文件中保存并执行时,我遇到错误并且必须终止终端以停止执行程序。
我已经通过if __name__ == '__main__':
和在此下创建了池并使用pool.close()
关闭池来纠正了这个问题。
我很想知道在使用multiprocessing
以及map
,apply
,apply_async
等关联功能时应遵循哪些最佳做法?我打算使用这个模块并行读取文件,希望将它应用于少数ML算法,以加快这个过程。
答案 0 :(得分:4)
你必须把它放在if __name__
中的原因是因为当python产生一个新进程时,它会有效地导入这个模块 - 因此试图再次运行不在if __name__
块中的任何代码再一次。
最佳做法是将事物保存在合理命名的小型可测试功能中。有一个' main()'函数,然后从if __name__
块调用。
避免全局状态(和模块级变量)。它只是让事情变得复杂。相反,想一想将流程传递给流程或从流程传递。这可能很慢,因此首先考虑如何尽可能少地发送数据是有用的。例如,如果您有一个大的配置对象,而不是将整个配置对象发送到每个进程,请将您的流程函数拆分为只需要实际使用的一个或两个属性,然后发送它们。
当事情连续发生时,测试事情会容易得多,因此以这样的方式编写事物,使其顺序发生,而不是使用map
或其他任何可以实现的事情更容易。
分析事物是一个好主意,因为整个产生新进程有时最终会比在一个线程中完成所有操作更慢。 gevent模块也非常酷 - 如果你的程序是网络绑定的,那么gevent有时可以比使用多处理更快地并行处理。
答案 1 :(得分:2)
提到的python文档很好 - 请查看Using Python's multiprocessing.Process class。这个问题有一些类似的想法。我还建议您查看https://www.ibm.com/developerworks/aix/library/au-multiprocessing/。它是在python中,并突出了一些很好的pythonic方法来进行多处理。
答案 2 :(得分:1)
官方Python文档有很多用法示例。这可能是学习最佳实践的最佳方式:http://docs.python.org/2/library/multiprocessing.html
答案 3 :(得分:0)
根据我自己的经验(也是有限的),我可以就多处理如何工作以及如何使用它分享以下见解。我没有发现python.org手册的描述性或图形性很好,因此我阅读了代码。对于每个有相同印象的人……到目前为止,这是我可以弥补的:
Process
或它们的列表对于以少数功能一对一运行功能2进程为目标很有用。Pool
处理一组Process
es(进程池)之间的可分批工作负载(高级任务/命令)的分配。Pool
用于处理器绑定(具有可批量输入/输出的高处理器负载)和pool.ThreadPool
用于IO绑定(具有单独的输入/输出的低处理器负载)任务。Process
,Pool
,Thread
和ThreadPool
之间的数据传输,请使用queues.Queue
和子类(如果结果顺序很重要)或{ {1}}与Pipe
到进程或线程的一对一映射。PipeConnection
,BaseProxy
,Namespace
,Queue
s的变量,或用于设置Pool
/ {{不同进程之间的1}} / Barrier
/ Lock
/ RLock
s使用Sempaphore
类。Condition
,请使用Manager
处理它们,并尝试将密集的计算过程与与GIL
相关的计算分开(例如,解析复杂的数据结构,等),然后与Manager
或共享的GIL
连接。Pipe
可以将不同数量的进程分配给不同的任务。否则,只需实现一个具有多个映射的Queue
或应用方法调用即可。Pool
和多个Pool
或Pool()
来计算基于彼此中间结果的顺序并行计算任务。为了使任务彼此同步,映射功能及其方法Pool.(star)map_async()
返回的Pool.(star)map()
实例是正确的选择。ApplyResult()
时,ApplyResult().ready()/.wait()/.get()/.successful()
被初始化,它是import multiprocessing
的子类,但没有_current_process = MainProcess()
,BaseProcess
,target
,{ {1}},基本上是已经运行的python内核中所有其他args
的句柄对象,这些内核导入了kwargs
。_paraent_pid
是Pool的类似API,可能也共享相似的体系结构Process
基于3个守护进程线程multiprocessing
,pool.ThreadPool
和Pool
,它们与1个内部Pool._task_handler
Pool._worker_handler
和2个内部{ {1}}个Pool._result_handler
和queue.Queue()
。Pool._taskqueue
是一个字典,其中包含所有SimpleQueue
和子方法调用中的Pool._inqueue
和子类实例,其中Pool._outqueue
中的全局Pool._cache
为{{1} }。ApplyResults
中找到了{li1的Pool.appy_async()/_map_async()
和ApplyResults._job
的子类,并返回了job_counter()
和子方法。key
和ApplyResult
之间的区别在于,Pool
强制/锁定主进程,以等待所有结果被计算并存储在返回对象Pool._cache
中。 Pool.apply_async()/._map_async()
/ Pool.map()
游泳池`:
Pool.map_async()
:传送Pool.map() == Pool.map_async().get()
/ etc的高级作业。从应用方法到ApplyResult()
切成任务批次。Queue
:以批量方式将作业传递给迭代器?从SimpleQueues in
到Pool.taskqueue
Pool.apply_async()/.map_async()
:将结果从Pool._task_handler
(由Pool._inqueue
初始化)传送到Pool._task_handler
,Pool._pool.Process(target=worker, ...)
再次将它们放入{{1 }}缓存在Pool._outqueue
中。Pool._pool.Process(target=worker, ...)
有返回对象,则Pool._worker_handler
将结果保存为列表。否则Pool._result_handler
只是同步方法(即结果状态调用方法)的句柄。_set()
,ApplyResult
,Pool._cache[self._job]
,ApplyResult
/ {{1} }。
func
只是一个返回实际ApplyResult()
类实例中的2个实例的方法。queues.JoinableQueue