如何并行化一个简单的 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 上运行。

并行化此代码的最简单方法是什么?

原文由 memyself 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 401
2 个回答

由于全局解释器锁 (GIL),在 CPython 上使用多个线程不会为纯 Python 代码提供更好的性能。我建议改用 multiprocessing 模块:

 pool = multiprocessing.Pool(4)
out1, out2, out3 = zip(*pool.map(calc_stuff, range(0, 10 * offset, offset)))

请注意,这在交互式解释器中不起作用。

为了避免 GIL 周围的常见 FUD:无论如何,在这个例子中使用线程不会有任何优势。你 在这里使用进程,而不是线程,因为它们避免了一大堆问题。

原文由 Sven Marnach 发布,翻译遵循 CC BY-SA 3.0 许可协议

from joblib import Parallel, delayed
def process(i):
    return i * i

results = Parallel(n_jobs=2)(delayed(process)(i) for i in range(10))
print(results)  # prints [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

以上在我的机器上运行良好(Ubuntu,包 joblib 是预安装的,但可以通过 pip install joblib 安装)。

取自 https://blog.dominodatalab.com/simple-parallelization/


Edit on Mar 31, 2021: On joblib , multiprocessing , threading and asyncio

  • joblib 在上面的代码中使用 import multiprocessing 在引擎盖下(因此多个进程,这通常是跨内核运行 CPU 工作的最佳方式 - 因为 GIL)
  • 您可以让 joblib 使用多线程而不是多进程,但这(或直接使用 import threading )只有在线程在 I/O 上花费大量时间(例如读/写)时才有用到磁盘,发送 HTTP 请求)。对于 I/O 工作,GIL 不会阻塞另一个线程的执行
  • 从 Python 3.7 开始,作为 threading 的替代方案,您可以使用 asyncio 并行工作,但同样的建议适用于 import threading (尽管与后者相比,仅使用 1 个线程; 从好的方面来说, asyncio 有很多有助于异步编程的好特性)
  • 使用多个进程会产生开销。想一想:通常,每个进程都需要初始化/加载运行计算所需的一切。您需要检查一下上面的代码片段是否改善了您的挂钟时间。这是另一个,我确认 joblib 产生更好的结果:
 import time
from joblib import Parallel, delayed

def countdown(n):
    while n>0:
        n -= 1
    return n

t = time.time()
for _ in range(20):
    print(countdown(10**7), end=" ")
print(time.time() - t)
# takes ~10.5 seconds on medium sized Macbook Pro

t = time.time()
results = Parallel(n_jobs=2)(delayed(countdown)(10**7) for _ in range(20))
print(results)
print(time.time() - t)
# takes ~6.3 seconds on medium sized Macbook Pro

原文由 tyrex 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏