我的python代码中有一个嵌套的for循环,看起来像这样:
results = []
for azimuth in azimuths:
for zenith in zeniths:
# Do various bits of stuff
# Eventually get a result
results.append(result)
我想在我的4核机器上并行化这个循环来加速它。看看IPython并行编程文档(http://ipython.org/ipython-doc/dev/parallel/parallel_multiengine.html#quick-and-easy-parallelism),似乎有一种简单的方法可以使用{{1}并行化迭代操作。
但是,要做到这一点,我需要将循环中的代码作为一个函数(这很容易),然后映射到这个函数。我遇到的问题是我无法获得一个数组来映射这个函数。 map
生成一个迭代器,我似乎无法使用map函数。
我试图在这里使用地图咆哮错误的树吗?有没有更好的方法呢?或者是否有某种方法可以使用itertools.product()
然后使用映射到结果的函数进行并行执行?
答案 0 :(得分:10)
要并行化每个调用,您只需要为每个参数获取一个列表。您可以使用itertools.product
+ zip
来获取此信息:
allzeniths, allazimuths = zip(*itertools.product(zeniths, azimuths))
然后你可以使用map:
amr = dview.map(f, allzeniths, allazimuths)
为了更深入地了解这些步骤,这里有一个例子:
zeniths = range(1,4)
azimuths = range(6,8)
product = list(itertools.product(zeniths, azimuths))
# [(1, 6), (1, 7), (2, 6), (2, 7), (3, 6), (3, 7)]
所以我们有一个“对列表”,但我们真正想要的是每个参数的单个列表,即“一对列表”。这正是稍微奇怪的zip(*product)
语法让我们:
allzeniths, allazimuths = zip(*itertools.product(zeniths, azimuths))
print allzeniths
# (1, 1, 2, 2, 3, 3)
print allazimuths
# (6, 7, 6, 7, 6, 7)
现在我们只将我们的函数映射到这两个列表,以并行化嵌套for循环:
def f(z,a):
return z*a
view.map(f, allzeniths, allazimuths)
没有什么特别的,只有两个 - 这个方法应该扩展到任意数量的嵌套循环。
答案 1 :(得分:9)
我假设您使用的是IPython 0.11或更高版本。首先定义一个简单的函数。
def foo(azimuth, zenith):
# Do various bits of stuff
# Eventually get a result
return result
然后使用IPython的优秀并行套件来并行化您的问题。首先通过在终端窗口中启动集群来启动连接了5个引擎的控制器(#CPU + 1)(如果安装了IPython 0.11或更高版本,则该程序应该存在):
ipcluster start -n 5
在您的脚本中连接到控制器并传输您的所有任务。控制器会处理所有事情。
from IPython.parallel import Client
c = Client() # here is where the client establishes the connection
lv = c.load_balanced_view() # this object represents the engines (workers)
tasks = []
for azimuth in azimuths:
for zenith in zeniths:
tasks.append(lv.apply(foo, azimuth, zenith))
result = [task.get() for task in tasks] # blocks until all results are back
答案 2 :(得分:1)
我对IPython并不熟悉,但一个简单的解决方案似乎只是将外循环并行化。
def f(azimuth):
results = []
for zenith in zeniths:
#compute result
results.append(result)
return results
allresults = map(f, azimuths)
答案 3 :(得分:1)
如果您确实想要并行运行代码,请使用concurrent.futures
import itertools
import concurrent.futures
def _work_horse(azimuth, zenith):
#DO HEAVY WORK HERE
return result
futures = []
with concurrent.futures.ProcessPoolExecutor() as executor:
for arg_set in itertools.product(zeniths, azimuths):
futures.append(executor.submit(_work_horse, *arg_set))
executor.shutdown(wait=True)
# Will time out after one hour.
results = [future.result(3600) for future in futures]
答案 4 :(得分:1)
如果要保留循环的结构,可以尝试使用Ray(docs),它是用于编写并行和分布式Python的框架。一个要求是,您必须将可以并行化为其自身功能的工作分开。
您可以这样导入Ray:
setTimeout(function(){
clickButton(buttons, i)
}, 2000);
然后,您的脚本将如下所示:
import ray
# Start Ray. This creates some processes that can do work in parallel.
ray.init()