Python与列表推导式的性能
假设你在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