如何在python中并发计算平均值?

How to calculate average concurrently in python?

我在 python 中定义了两种计算平均值的正确方法。

def avg_regular(values):
    total = 0
    for value in values:
        total += value
    return total/len(values)

def avg_concurrent(values):
    mean = 0
    num_of_values = len(values)
    for value in values:
        #calculate a small portion of the average for each num and add to the total
        mean += value/num_of_values  
    return mean

第一个函数是计算平均值的常规方法,但我写了第二个函数,因为循环的每个 运行 都不依赖于前面的 运行。因此理论上可以并行计算平均值。

然而,"parallel" 一个(没有并行 运行ning)比普通的多花费大约 30% 的时间。

我的假设是否正确并且值得损失速度? 如果是,我怎样才能使第二个函数 运行 成为第二个函数?

如果不是,我哪里错了?

你实现的代码基本上就是(a1+a2+ ... + an) / n(a1/n + a2/n + ... + an/n)的区别。结果是一样的,但在第二个版本中有更多的操作(即(n-1)更多的除法),这会减慢计算速度。您声称在第二个版本中每个循环 运行 都独立于其他循环。在第一个循环中,我们需要以下信息来完成一个循环 运行: 运行 之前的 total 和当前 value。在第二个版本中,我们需要以下信息来完成一个循环运行:运行之前的mean,当前valuenum_of_values。正如您在第二个版本中看到的,我们甚至依赖更多的值!

但是我们如何在核心之间分配工作(这是多处理的目标)?我们可以只给一个核心值的前半部分,给第二个核心值的后半部分,即 ((a1+a2+ ... + a(n//2)) + ( a(n//2 +1) + ... + a(n)) / n)。是的,除以 n 的工作并没有在内核之间分配,但它是一条指令,所以我们并不关心。另外我们还需要把左总和右总相加,我们不能拆分,但同样它只是一个单一的操作。

所以我们要的代码运行:

def my_sum(values):
    total = 0
    for value in values:
        total += value
    return total

python 仍然存在问题 - 通常可以使用线程来进行计算,因为每个线程将使用一个核心。但是在那种情况下,必须注意您的程序不会 运行 进入竞争条件,并且 python 解释器本身也需要注意这一点。 CPython 认为这是不值得的,基本上一次只有 运行s 在一个线程中。一个基本的解决方案是通过 multiprocessing 使用多个进程。

from multiprocessing import Pool

if __name__ == '__main__':

    with Pool(5) as p:
        results = p.map(my_sum, [long_list[0:len(long_list)//2], long_list[len(long_list)//2:]))

    print(sum(results) / len(long_list)) # add subresults and divide by n

当然,多进程不是免费的。你需要分叉、复制东西等等,所以你不会像人们预期的那样获得 2 的加速。同样最大的减速实际上是使用 python 本身,它并没有真正针对快速数值计算进行优化。有多种解决方法,但使用 numpy 可能是最简单的。只需使用:

import numpy
print(numpy.mean(long_list))

这可能比 python 版本快得多。我不认为 numpy 在内部使用多处理,因此可以通过使用多个进程和快速实现(numpy 或其他用 C 编写的东西)来获得提升,但通常 numpy 足够快。