【问题标题】:How to calculate average concurrently in python?如何在python中同时计算平均值?
【发布时间】:2017-02-19 17:09:19
【问题描述】:

我在 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

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

但是,“并行”(没有并行运行)比普通的要多花大约 30% 的时间。

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

如果不是,我哪里做错了?

【问题讨论】:

  • 异步是什么意思?在 python asyncio 中执行异步 IO,但这并不能真正帮助您。您想加快计算速度吗?查看 numpy.如果您想在多个内核上运行,请查看多处理(python 线程不能同时运行 python 代码)。你的第二个版本做了更多的工作(每次除法和加法),所以我认为它需要更多时间并不令人惊讶。
  • @syntonym 对不起,我的意思是并行而不是异步,就像在多个线程中运行一样。我将如何为此使用多进程?
  • Ofc 第二个比较慢。更多的部门!
  • 您是追求速度还是只是想了解并行处理的多处理/计算?
  • @syntonym 我试图理解,但多处理的好处不是加快了速度吗?

标签: python python-3.x concurrency multiprocessing python-multiprocessing


【解决方案1】:

你实现的代码基本上就是(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 认为它不值得,基本上一次只能在一个线程中运行。一个基本的解决方案是通过多处理使用多个进程。

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 足够快。

【讨论】:

  • 我不确定,但我认为 Numpy 通常不使用多处理是对的。但是,我认为,它确实会尽可能使用向量/SIMD 指令,我认为这是提高速度的部分原因。
  • @Jarak 看起来 numpy 通过 BLAS 完成了一些计算工作,因此(使用优化版本时)它应该使用向量、SIMD、指令级并行等。此外,还可以使用多线程编译 BLAS ,但我不确定总和是否使用它。通常,python 相对较慢,因为它需要做很多事情(主要是创建 python 对象),并且简单地使用 numbacython 之类的东西应该会大大加快速度
猜你喜欢
  • 2013-12-18
  • 2011-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-26
  • 2019-02-07
相关资源
最近更新 更多