赞
踩
这个东西对于一些循环重复的操作,可以让你的程序加速好几倍,如果再加上编译的话,就更快了。所以,赶紧学起来吧。
前言中的场景如下:我们需要判断100个数是否为素数,判断一个是否为素数的代码如下:
def is_prime(n):
if n < 2:
return False
if n == 2:
return True
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
判断100个数,无非就是循环而已,这种就特别适合使用多进程,并行计算,理论上提升100倍的速度,不过我们的计算机cpu核心数一般并没有100个,所以实际上无法并行100个进程。
假设我们要判断如下的100个超大数是否为素数:
PRIMES = [112272535095293] * 100
from concurrent.futures import ProcessPoolExecutor
由于我们是并行的进程,所以,先输出的结果不一定会是最开始运行的进程。那这样,我们岂不是会搞乱?无法分辨输出的结果是对应哪个的?
不会的,因为我们定义的时候,会定义好每一个进程的标识,输出的时候可以既打印进程标识,又打印对应结果,所以并不会搞乱。
定义的方法是字典,其中键是job(任务),任务的定义方式如下,使用submit
,同时传入函数名称以及参数。然后值是我们的参数,其实这个值是我们随便定义的,不一定要是参数,之前我们不是说怕搞混吗?所以我们就填写参数作为进程标识。有人会问,job里面不是有n吗?这个不是已经是标识了嘛?问题是,我打印过job,不会显示n,而是一堆地址,你看不懂的。所以还是老实使用值来标识。
executor.submit(is_prime, n)#键
完整定义如下:
with ProcessPoolExecutor() as executor:
jobs = {executor.submit(is_prime, n): n for n in PRIMES}
根据前面所说,值是随便定义的,所以当然可以如下:
jobs = {executor.submit(is_prime,n): "is_prime({})".format(n) for n in PRIMES}
相当于更加可读了,更加标识这个进程。
from concurrent.futures import as_completed
上面执行了,我们需要打印结果。
with ProcessPoolExecutor() as executor:
jobs = {executor.submit(is_prime,n): "is_prime({})".format(n) for n in PRIMES}
for job in as_completed(jobs):
try:
print("job:{},result:{}".format(jobs[job],job.result()))
except Exception as e:
print(e)
部分结果如下:
job:is_prime(112272535095293),result:True
job:is_prime(112272535095293),result:True
job:is_prime(112272535095293),result:True
job:is_prime(112272535095293),result:True
job:is_prime(112272535095293),result:True
当然啦,我们100个素数由于都是一个数,所以打印出来一样,但是其实可以不一样。
我试过,我的笔记本是16核还是8核的,这个程序比正常的python程序挨个运行加速了3-4倍左右。
上面哪一个进程谁先执行完不知道,下面这个则是前面没完,后面的不会先完,后面的可能其实已经完了,但是前面没完,所以要等。速度不如上一节介绍的,大家看看就好。
with ProcessPoolExecutor() as executor:
try:
results = executor.map(is_prime,PRIMES)
for num, result in zip(PRIMES, results):
print('fib(%s) result is %s.' % (num, result))
except Exception as e:
print(e)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。