同时运行此循环的最佳方法?

Posted

技术标签:

【中文标题】同时运行此循环的最佳方法?【英文标题】:Best way to simultaneously run this loop? 【发布时间】:2021-03-07 12:16:10 【问题描述】:

我有以下代码:

data = [2,5,3,16,2,5]        

def f(x):       
    return 2*x

f_total = 0
for x in data:
    f_total += f(x)

print(f_total/len(data))

我想加快 for 循环。 (实际上代码更复杂,我想在具有许多处理核心的超级计算机中运行它)。我读过我可以使用multiprocessing 库来做到这一点,在那里我可以让python3同时运行不同的循环块,但我有点迷失了。

您能解释一下如何使用我的程序的这个最小版本吗?

谢谢!

【问题讨论】:

这能回答你的问题吗? How do I parallelize a simple Python loop? 超级计算机来自我的研究机构。 @ranka47 它可能会回答我的问题,但我无法完全理解,也许更详细/更简单的答案对我有用? 【参考方案1】:
import multiprocessing
from numpy import random

"""
This mentions the number of worker threads that you want to run in parallel.
Depending on the number of cores in your system you should choose the appropriate
number of threads. When you call 'map' function it will distribute the input
values in that many parts
"""
NUM_CORES = 6
data = random.rand(100, 1)

"""
+2 so that the cores are not left idle in case a thread is waiting for I/O. 
Choose by performing an empirical analysis depending on the function you are trying to compute.
It could match up to NUM_CORES as well. You can vary the chunksize as well depending on the size of 'data' that you have. 
"""
NUM_THREADS = NUM_CORES+2
CHUNKSIZE = int(len(data)/(NUM_THREADS))    


def f(x):       
    return 2*x

# This takes care of creating pool of worker threads which will be assigned the jobs
pool = multiprocessing.Pool(NUM_THREADS)

# map vs imap. If the data is large go for imap else map is also good.
it = pool.imap(f, data, chunksize=CHUNKSIZE)

f_total = 0
# Iterate and sum up the result
for value in it:
    f_total += sum(value)

print(f_total/len(data))

Why choose imap over map?

【讨论】:

非常感谢您提供如此详细的回答!所以我想我可以想象一个工人是我计算机中的一个单核,在一个特定的独立任务中工作,或者它可以是我喜欢的任何数字吗?如果是这样,如何明智地选择工人数量? 另外,如果int(len(data)/(NUM_CORES-2)) 不等于len(data),python 会知道它需要分配一些额外的迭代来完全耗尽data 最后,我看不出sum(value) 的必要性,因为value 已经是一个数字,所以仅仅做f_total += value 还不够吗?我可能遗漏了什么。 奖励:我一直在玩NUM_CORES,发现即使我的电脑有 8 个(通过os.cpu_count()),如果我输入更大的数字(不是更大),比如NUM_CORES=10我得到了更好的性能(至少对于这个愚蠢的例子,尽管数据量更大)。如何为NUM_CORES 选择最佳号码? (我想这也和我的第一个问题有关) 它是sum(value),因为imap 正在返回list。您也可以将其替换为value[0]。关于 NUM_THREADS 的选择我错了。你可以给予更多的价值,但在一定程度上。我不知道如何选择线程数的公式。我建议做一个实证分析。当线程等待 I/O 时,更多会涉及使用核心。但是,非常高的值可能会由于上下文切换而增加开销。

以上是关于同时运行此循环的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章

针对IF语句测试范围值数组的最佳方法

在循环中一次处理 X 个线程的最佳方法?

以编程方式确定是不是可以在对象上运行 for 循环的最佳解决方案

从并行运行脚本更新值的最佳方法 - Python

与 kotlin 异步运行代码的最佳方法

我如何在 gitlab-ci 中同时运行循环?