Python与列表推导式的性能

9 投票
3 回答
4244 浏览
提问于 2025-04-16 18:49

假设你在Python中有一个列表推导式,比如说:

Values = [ f(x) for x in range( 0, 1000 ) ]

这里的f只是一个普通的函数,没有副作用。所以所有的计算都是可以独立进行的。

那么,Python能否通过一些方法,比如在多核CPU上共享内存来提高这个列表推导式的性能,相比于那种“显而易见”的实现呢?

3 个回答

0

试试看下面的代码能不能更快:

Values = map(f,range(0,1000))

这是一种函数式编程的写法

另一个想法是把代码中所有的Values都换成生成器表达式

imap(f,range(0,1000))  # Python < 3

map(f,range(0,1000))  # Python 3
8

不,Python不会自动为你实现并行处理。实际上,它做不到这一点,因为它无法证明各个数据项之间是独立的;这需要对程序进行大量的检查和验证,而在一般情况下,这是很难做到的。

如果你想要快速的多核并行处理,我推荐使用joblib库:

from joblib import delayed, Parallel
values = Parallel(n_jobs=NUM_CPUS)(delayed(f)(x) for x in range(1000))

我亲眼见过使用这个库时,速度几乎线性提升,而且它还有一个很棒的功能,就是可以将像Ctrl-C这样的信号传递给它的工作进程,这并不是所有的多进程库都具备的。

需要注意的是,joblib并不真正支持共享内存的并行处理:它是启动工作进程,而不是线程,因此在将数据发送给工作进程和将结果返回给主进程时,会产生一些通信开销。

10

在Python 3.2版本中,他们新增了一个叫做 concurrent.futures 的库,这个库很不错,可以用来同时处理多个问题。来看这个例子:

import math, time
from concurrent import futures

PRIMES = [112272535095293, 112582705942171, 112272535095293, 115280095190773, 115797848077099, 1099726899285419, 112272535095293, 112582705942171, 112272535095293, 115280095190773, 115797848077099, 1099726899285419]

def is_prime(n):
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def bench(f):
    start = time.time()
    f()
    elapsed = time.time() - start
    print("Completed in {} seconds".format(elapsed))

def concurrent():
    with futures.ProcessPoolExecutor() as executor:
        values = list(executor.map(is_prime, PRIMES))

def listcomp():
    values = [is_prime(x) for x in PRIMES]

在我的四核处理器上运行的结果:

>>> bench(listcomp)
Completed in 14.463825941085815 seconds
>>> bench(concurrent)
Completed in 3.818351984024048 seconds

撰写回答