主要内容:
- 小目标:掌握进程池
- 主要内容:进程池使用;
1. 进程池:
有没有一种方式:直接创建N个进程,然后直接将任务交给这些进程去执行?
有,进程池;
进程池相关方法:
apply_async与apply区别:
- apply:添加任务后,等待进程函数执行完,
- apply_async:添加任务后,立即返回,支持回调;原型如下:
#callback为回调函数pools.apply_async(func, args=(), kwds={}, callback=None, error_callback=None,)
直接看例子:
from multiprocessing import Poolimport timeimport osdef func(*args, **kwargs): # 定义进程函数 print('sub process id:', os.getpid()) time.sleep(1)if __name__ == "__main__": start = time.time() # 创建进程池,进程数为4 pools = Pool(4) for i in range(5): # 添加任务 pools.apply_async(func) # 关闭进程池,不在添加任务 pools.close() pools.join() print("cost time:", int(time.time()-start))
结果:
sub process id: 15536sub process id: 2788sub process id: 20288sub process id: 11020sub process id: 15536cost time: 2
2. 进程池处理结果获取方式;
一个例子:统计句子中有效单词数量;
#6个单词,长度为20wds = "this is test this is test"
2.1 思路1:ApplyResult
实现思路:
创建进程池;
对wds进程切分,每个单词为wd;
添加任务,每个进程函数统计每个wd长度,并返回长度;
通过ApplyResult接收
代码实现:
from multiprocessing import Poolimport timeimport osdef func(*args, **kwargs): # 定义进程函数 val = args[0] return len(val)if __name__ == "__main__": wds = "this is test this is test" # 创建进程池,进程数为4 pools = Pool(4) listr = [] # 切分字符串,并进程长度统计 for wd in wds.split(): # 添加任务,返回ApplyResult r = pools.apply_async(func, args=(wd,)) listr.append(r) # 关闭进程池,不在添加任务 pools.close() pools.join() # 通过ApplyResult获取长度 lens = 0 for r in listr: lens += r.get() print('wds lens:', lens)
结果:
wds lens: 20
2.2 思路2:回调函数
- 回调函数:将函数作为参数传递给其他函数,当这个函数被调用时,就被称为回调函数;
- 通过设置apply_async中的callback;
实现思路:
创建进程池;
对wds进程切分,每个单词为wd;
定义回调函数,参数为单词长度,操作计算单词长度累积和;
添加任务,每个进程函数统计每个wd长度,并指定回调函数;
通过回调函数进行长度统计
代码实现:
from multiprocessing import Poolimport timeimport osdef func(*args, **kwargs): # 定义进程函数 val = args[0] return len(val)glens = 0def callback(val): global glens glens += valif __name__ == "__main__": wds = "this is test this is test" # 创建进程池,进程数为4 pools = Pool(4) listr = [] # 切分字符串,并进程长度统计 for wd in wds.split(): # 添加任务,返回ApplyResult r = pools.apply_async(func, args=(wd,), callback=callback) listr.append(r) # 关闭进程池,不在添加任务 pools.close() pools.join() print('glens:', glens)
结果:glens: 20
分析:callback在进程函数执行完之后进行调用;
总结
进程池优点:
一次性创建N多进程,减少系统常见进程开销;
使用灵活,接口简单;