如何用Python将巨大的嵌套循环整齐地划分为8个(或更多)进程?
这次我遇到了一个“设计”问题。使用Python,我需要实现一个数学算法,这个算法需要5个参数。为了找到这5个参数的最佳组合,我用了5层嵌套循环来列举所有可能的组合,范围是我设定的。但是,完成这个过程所需的时间超出了我的预期。所以我觉得是时候使用多线程了……
在这些嵌套循环的核心任务中,主要是计算和保存结果。在我现在的代码中,每次计算的结果都会添加到一个列表中,最后程序结束时再把这个列表写入一个文件。
由于我在任何语言中都没有太多多线程的经验,更不用说Python了,我想请教一下,这个问题的结构应该是什么样的。具体来说,如何动态地将计算任务分配给线程,以及线程如何保存结果,最后又如何把所有结果合并成一个文件。我希望线程的数量可以调整。
如果能提供一些代码示例,那将非常有帮助。
非常感谢你的时间,我很感激。
#第二天更新: 感谢所有有帮助的回答,现在我知道应该使用多进程而不是多线程。我总是把这两个概念搞混,因为我认为如果是多线程的话,操作系统会在有多个处理器时自动使用它们来运行程序。我会找时间今晚亲自尝试一下多进程。
3 个回答
假设这是一个计算量很大的问题(所以它主要依赖CPU),在Python中,多线程对你帮助不大,因为有个叫做GIL的东西。
不过,你可以把计算分散到多个进程中,这样就能利用额外的CPU核心。最简单的方法就是使用multiprocessing
这个库。
在这个库的文档页面上,有很多关于如何使用multiprocessing
的例子。
在Python中,多线程并不能解决这个问题,因为Python并不是同时执行多个线程(它主要是用来处理输入输出的并发)。
你应该使用 multiprocessing
,或者使用一个更友好的工具,比如joblib:
from joblib import Parallel, delayed
# -1 == use all available processors
results = Parallel(n_jobs=-1)(delayed(evaluate)(x) for x in enum_combinations())
print best_of(results)
这里的 enum_combinations
是用来列举你五个参数的所有组合;你可以通过在嵌套循环的底部加一个 yield
来实现。
joblib 会把这些组合分配到多个工作进程中,并且会处理一些负载均衡的问题。
你可以试试我写的一个叫jug的库,它可以解决类似的问题。你的代码可能会像下面这样:
from jug import TaskGenerator
evaluate = TaskGenerator(evaluate)
for p0 in [1,2,3]:
for p1 in xrange(10):
for p2 in xrange(10,20):
for p3 in [True, False]:
for p4 in xrange(100):
results.append(evaluate(p0,p1,p2,p3,p4))
现在你可以运行任意数量的进程(如果你有计算机集群的访问权限,甚至可以跨网络运行)。