我如何并行化一个简单的Python循环?
这可能是一个微不足道的问题,但我如何在python中并行化下面的循环?
# setup output lists
output1 = list()
output2 = list()
output3 = list()
for j in range(0, 10):
# calc individual parameter value
parameter = j * offset
# call the calculation
out1, out2, out3 = calc_stuff(parameter = parameter)
# put results into correct output list
output1.append(out1)
output2.append(out2)
output3.append(out3)
我知道如何在Python中启动单线程,但我不知道如何“收集”结果。
多个进程也可以,无论这种情况最简单。 我目前使用Linux,但代码应该在Windows和Mac上运行。
并行化这些代码的最简单方法是什么?
由于全局解释器锁定(GIL),在CPython上使用多个线程不会为纯Python代码提供更好的性能。 我建议使用multiprocessing
模块:
pool = multiprocessing.Pool(4)
out1, out2, out3 = zip(*pool.map(calc_stuff, range(0, 10 * offset, offset)))
请注意,这在交互式解释器中不起作用。
为了避免GIL周围的通常的FUD:无论如何,对于这个示例使用线程没有任何优势。 你想在这里使用进程,而不是线程,因为它们避免了一堆问题。
为了并行化一个简单的for循环,joblib为多处理的原始使用带来了很大的价值。 不仅是简短的语法,而且还包括当迭代速度非常快(消除开销)或捕获子进程回溯时的透明迭代,以获得更好的错误报告。
免责声明:我是joblib的原作者。
并行化这些代码的最简单方法是什么?
我真的很喜欢concurrent.futures
自3.2版本对于这一点,在Python3可用-并通过反向移植到2.6和2.7 PyPI上。
您可以使用线程或进程并使用完全相同的界面。
多
把它放在一个文件中 - futuretest.py:
import concurrent.futures
import time, random # add some random sleep time
offset = 2 # you don't supply these so
def calc_stuff(parameter=None): # these are examples.
sleep_time = random.choice([0, 1, 2, 3, 4, 5])
time.sleep(sleep_time)
return parameter / 2, sleep_time, parameter * parameter
def procedure(j): # just factoring out the
parameter = j * offset # procedure
# call the calculation
return calc_stuff(parameter=parameter)
def main():
output1 = list()
output2 = list()
output3 = list()
start = time.time() # let's see how long this takes
# we can swap out ProcessPoolExecutor for ThreadPoolExecutor
with concurrent.futures.ProcessPoolExecutor() as executor:
for out1, out2, out3 in executor.map(procedure, range(0, 10)):
# put results into correct output list
output1.append(out1)
output2.append(out2)
output3.append(out3)
finish = time.time()
# these kinds of format strings are only available on Python 3.6:
# time to upgrade!
print(f'original inputs: {repr(output1)}')
print(f'total time to execute {sum(output2)} = sum({repr(output2)})')
print(f'time saved by parallelizing: {sum(output2) - (finish-start)}')
print(f'returned in order given: {repr(output3)}')
if __name__ == '__main__':
main()
这里是输出:
$ python3 -m futuretest
original inputs: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
total time to execute 33 = sum([0, 3, 3, 4, 3, 5, 1, 5, 5, 4])
time saved by parallellizing: 27.68999981880188
returned in order given: [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
多线程
现在将ProcessPoolExecutor
更改为ThreadPoolExecutor
,然后再次运行该模块:
$ python3 -m futuretest
original inputs: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
total time to execute 19 = sum([0, 2, 3, 5, 2, 0, 0, 3, 3, 1])
time saved by parallellizing: 13.992000102996826
returned in order given: [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
现在你已经完成了多线程和多处理!
关于性能和使用两者的注意事项。
抽样太小而无法比较结果。
但是,我怀疑多线程将比一般的多处理更快,特别是在Windows上,因为Windows不支持分叉,因此每个新进程都需要一段时间才能启动。 在Linux或Mac上,它们可能会更接近。
您可以在多个进程中嵌套多个线程,但建议不要使用多个线程来分离多个进程。
链接地址: http://www.djcxy.com/p/79379.html上一篇: How do I parallelize a simple Python loop?
下一篇: Can't understand python shallow copy when working with int and str