请注意:在之前的章节中已经涉及了关于并行&并发的概念,请各位移步python中级第十七课查看相关概念,这里不再赘述。
目的:利用多个CPU同时工作提高执行效率
方法:
这里我们借鉴了一个很好的例子,关于解析阿帕奇web服务器中日志的例子。通过脚本实现获取访问过robot.txt文件的主机数据。
#log格式类似于如下;
'''
122.123.2.12 - - [10/jul/2020:03:21:50 -0543] "GET /robot.txt ..." 200 11873
122.123.6.2 - - [10/jul/2020:03:21:51 -0543] "GET /ply/ ..." 200 11873
...解析出访问robot.txt的主机 -----
'''
import gzip
import io
import glob
from concurrent import futures
def find_robots(filename):
robot = set()
with gzip.open(filename) as f:
for line in io.TextIOWrapper(f,encoding='ascii'):
fields = line.split()
if fields[6] == '/robot.txt':
robot.update(fields[0])
return robot
def find_all_robots(logdir):
files = glob.glob(logdir+'/*.log.gz')
all_robots = set()
with futures.ProcessPoolExecutor() as pool:#进程池
for x in pool.map(find_robots, files):#进程池映射
all_robots.update(x)# 更新set集合
return all_robots
if __name__ == '__main__':
robots = find_all_robots('logs')
for ip in robots:
print(ip)
ProcessPoolExecutor最经典的用法如下:
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor(N) as pool:
...
do work in parallel(并发) using pool
...
这里的N指的就是系统检测到可用的CPU个数,进程池一直会运行直到with语句执行完,但是,程序会一直等待所有任务提交后处理完成才会停止。提到的任务中的函数必须定义成普通函数的形式(实例方法,闭包或者其他类型的可调用对象均不行)。有两种方法可以提交任务,一种是上边提到的映射map,还有一种是pool.submit(),后者适用于手动提交一个单独的任务。如果是手动提交,则结果是一个Future实例,要获取结果得使用result()函数,这么做会阻塞进程,直到完成了计算并将计算结果返回给进程池为止。