
文章目录简介线程池进程池简介concurrent.futures是 Python 标准库中用于简化并发编程的高级工具它通过提供线程池ThreadPoolExecutor和进程池ProcessPoolExecutor两大核心组件将底层复杂的多线程与多进程管理封装成了统一且简洁的接口让开发者无需手动处理资源创建、销毁与同步等繁琐细节即可根据任务特性I/O密集型用线程池CPU密集型用进程池轻松、高效地实现任务的并发执行与结果收集。线程和进程的区别在于前者处于并发模式即单核 CPU 通过快速切换任务交替执行多个任务后者处于并行模式即多核 CPU 同时执行多个任务。线程池下面是官网提供的示例这里只是把测试的网址更换了一下。importconcurrent.futuresascfimporturllib.request URLS[http://www.google.com/,https://docs.python.org/,http://tencent.com/,http://www.baidu.com/,https://www.britannica.com/]defload_url(url,timeout):withurllib.request.urlopen(url,timeouttimeout)asconn:returnconn.read()withcf.ThreadPoolExecutor(max_workers5)asexecutor:# 开始加载操作并以每个 Future 对象的 URL 对其进行标记future_to_url{executor.submit(load_url,url,10):urlforurlinURLS}forfutureincf.as_completed(future_to_url):urlfuture_to_url[future]try:datafuture.result()exceptExceptionasexc:print(%r generated an exception: %s%(url,exc))else:print(%r page is %d bytes%(url,len(data)))测试结果如下可见其并没有按照我们载入URLS的顺序挨个返回。http://www.baidu.com/pageis29506byteshttp://tencent.com/pageis173949byteshttps://www.britannica.com/generated an exception:HTTP Error403:Forbiddenhttp://www.google.com/generated an exception:urlopen error timed outhttps://docs.python.org/generated an exception:urlopen error _ssl.c:1015:The handshake operation timed out代码中无需深究load_url这只是个测试函数而已将其替换为虚假的延时操作也完全可以。【ThreadPoolExecutor】用于创建线程池其输入参数max_workers即为最大线程数。在Python3.8以上版本中其默认值为min ( 32 , C 4 ) \min(32, C 4)min(32,C4)C CC是CPU数即其默认线程数在5 55到32 3232之间。在代码中将线程池封在with域中从而确保线程用完后被迅速清理。【submit】用于向线程池中提交一个异步任务并立即返回代表该任务执行状态的Future对象。其输入参数可分为两部分第一个参数是线程中将要运行的函数剩下的参数是这个函数的参数。【as_completed】在接收一组Future对象后根据它们实际执行完成的先后顺序逐个产出这些 Future 对象。在Future对象中【result】即为函数运行的返回值。进程池进程池ProcessPoolExecutor和线程池ThreadPoolExcutor的核心方法、成员和上下文管理器完全相同。但是进程池实际上是对multiprocessing的封装Python在创建子进程时默认使用spawn这种方法会启动一个全新的 Python 解释器并重新导入主脚本。因此如果像上面那样随意把代码写在.py文件里子进程在导入主脚本时会再次执行到创建进程的代码从而导致无限递归创建子进程最终崩溃。其解决方案也很简单只需将其写在if __name__ __main__代码块中示例如下# 前面的代码与ThreadPoolExecutor相同if__name____main__:withcf.ProcessPoolExecutor(max_workers5)asexecutor:# 开始加载操作并以每个 Future 对象的 URL 对其进行标记future_to_url{executor.submit(load_url,url,10):urlforurlinURLS}forfutureincf.as_completed(future_to_url):urlfuture_to_url[future]try:datafuture.result()exceptExceptionasexc:print(%r generated an exception: %s%(url,exc))else:print(%r page is %d bytes%(url,len(data)))