在Python 的线程中运行协程的方法


Posted in Python onFebruary 24, 2020

在一篇文章 理解Python异步编程的基本原理 这篇文章中,我们讲到,如果在异步代码里面又包含了一段非常耗时的同步代码,异步代码就会被卡住。

那么有没有办法让同步代码与异步代码看起来也是同时运行的呢?方法就是使用事件循环的.run_in_executor()方法。

我们来看一下 Python 官方文档[1]中的说法:

在Python 的线程中运行协程的方法

那么怎么使用呢?还是以非常耗时的递归方式计算斐波那契数列的这个函数为例:

def sync_calc_fib(n): 
 if n in [1, 2]: 
 return1 
 return sync_calc_fib(n - 1) + sync_calc_fib(n - 2) 
async def calc_fib(n): 
 result = sync_calc_fib(n) 
 print(f'第 {n} 项计算完成,结果是:{result}') 
 return result

我们现在需要用 aiohttp 访问一个延迟5秒的网页,同时计算斐波那契数列第36项。

首先我们看看单独计算第36项需要5秒钟:

在Python 的线程中运行协程的方法

我们再来看看如果直接把这计算斐波那契数列和请求网站的两个异步任务放在一起“并行”,实际时间是两个任务的时间叠加:

具体原因我在上一篇文章里面已经做了说明。

在Python 的线程中运行协程的方法

现在,我想让两个任务“同时运行”,于是就可以这样修改代码:

import aiohttp 
import asyncio 
import time 
from concurrent.futures import ThreadPoolExecutor 
async def request(sleep_time): 
 async with aiohttp.ClientSession() as client: 
 resp = await client.get(f'http://127.0.0.1:8000/sleep/{sleep_time}') 
 resp_json = await resp.json() 
 print(resp_json) 
def sync_calc_fib(n): 
 if n in [1, 2]: 
 return 1 
 return sync_calc_fib(n - 1) + sync_calc_fib(n - 2) 
def calc_fib(n): 
 result = sync_calc_fib(n) 
 print(f'第 {n} 项计算完成,结果是:{result}') 
 return result 
async def main(): 
 start = time.perf_counter() 
 loop = asyncio.get_event_loop() 
 with ThreadPoolExecutor(max_workers=4) as executor: 
 tasks_list = [ 
  loop.run_in_executor(executor, calc_fib, 36), 
  asyncio.create_task(request(5)) 
 ] 
 await asyncio.gather(*tasks_list) 
 end = time.perf_counter() 
 print(f'总计耗时:{end - start}') 
asyncio.run(main())

运行效果如下图所示:

在Python 的线程中运行协程的方法

在5秒钟的时间,就把计算斐波那契数列和请求5秒延迟的网站都做完了。

实现这样的转变,关键的代码就是:loop.run_in_executor(executor, calc_fib, 36)

其中的 loop就是主线程的事件循环(event loop),它是用来调度同一个线程里面的多个协程。

executor是我们使用ThreadPoolExecutor(max_workers=4)创建的一个有4个线程的线程池,calc_fib是一个耗时的同步函数,36是传入calc_fib的参数。loop.run_in_executor(executor, calc_fib, 36)的意思是说:

  • 把calc_fib函数放到线程池里面去运行
  • 给线程池增加一个回调函数,这个回调函数会在运行结束后的下一次事件循环把结果保存下来。

请注意上图中红色箭头对应的calc_fib这是一个同步函数,请与上一篇文章中的异步函数区分开。run_in_executor的第二个参数需要是一个同步函数的函数名。

在上面的例子中,我们创建的是有4个线程的线程池。所以这个线程池最多允许4个阻塞式的同步函数“并行”。

总结

到此这篇关于在Python 的线程中运行协程的方法的文章就介绍到这了,更多相关python线程中运行协程内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python爬虫常用的模块分析
Aug 29 Python
遍历python字典几种方法总结(推荐)
Sep 11 Python
Python中list初始化方法示例
Sep 18 Python
python字典DICT类型合并详解
Aug 17 Python
Python竟能画这么漂亮的花,帅呆了(代码分享)
Nov 15 Python
python内置函数:lambda、map、filter简单介绍
Nov 16 Python
python使用Matplotlib画饼图
Sep 25 Python
python 快速把超大txt文件转存为csv的实例
Oct 26 Python
python把ipynb文件转换成pdf文件过程详解
Jul 09 Python
Python自动化测试笔试面试题精选
Mar 12 Python
关于Python 中的时间处理包datetime和arrow的方法详解
Mar 19 Python
python实现经纬度采样的示例代码
Dec 10 Python
Python 爬取必应壁纸的实例讲解
Feb 24 #Python
Python unittest工作原理和使用过程解析
Feb 24 #Python
Python 剪绳子的多种思路实现(动态规划和贪心)
Feb 24 #Python
用python介绍4种常用的单链表翻转的方法小结
Feb 24 #Python
关于多元线性回归分析——Python&SPSS
Feb 24 #Python
使用 pytorch 创建神经网络拟合sin函数的实现
Feb 24 #Python
sklearn+python:线性回归案例
Feb 24 #Python
You might like
PHP内核探索:变量存储与类型使用说明
2014/01/30 PHP
zf框架的session会话周期及次数限制使用示例
2014/03/13 PHP
PHP正则替换函数preg_replace和preg_replace_callback使用总结
2014/09/22 PHP
Laravel 解决419错误 -ajax请求错误的问题(CSRF验证)
2019/10/25 PHP
JS setCapture 区域外事件捕捉
2010/03/18 Javascript
分享27款非常棒的jQuery 表单插件
2011/03/28 Javascript
JS自定义功能函数实现动态添加网址参数修改网址参数值
2013/08/02 Javascript
JS小游戏之仙剑翻牌源码详解
2014/09/25 Javascript
js编写当天简单日历效果【实现代码】
2016/05/03 Javascript
Javascript 跨域知识详细介绍
2016/10/30 Javascript
Bootstrap Table使用整理(四)之工具栏
2017/06/09 Javascript
js获取地址栏参数的两种方法
2017/06/27 Javascript
seajs模块压缩问题与解决方法实例分析
2017/10/10 Javascript
javascript实现小型区块链功能
2019/04/03 Javascript
微信小程序上传帖子的实例代码(含有文字图片的微信验证)
2020/07/11 Javascript
python3使用urllib示例取googletranslate(谷歌翻译)
2014/01/23 Python
Python使用poplib模块和smtplib模块收发电子邮件的教程
2016/07/02 Python
Python 数据结构之队列的实现
2017/01/22 Python
解决pycharm无法调用pip安装的包问题
2018/05/18 Python
Django 对象关系映射(ORM)源码详解
2019/08/06 Python
Python迭代器模块itertools使用原理解析
2019/12/11 Python
Pytorch转keras的有效方法,以FlowNet为例讲解
2020/05/26 Python
python dir函数快速掌握用法技巧
2020/12/09 Python
pycharm配置QtDesigner的超详细方法
2021/01/25 Python
幼儿园新学期寄语
2014/01/18 职场文书
战略合作意向书范本
2014/04/01 职场文书
爱护公共设施的标语
2014/06/24 职场文书
中专毕业生的自荐书
2014/07/01 职场文书
出差报告格式模板
2014/11/06 职场文书
技术转让协议书
2016/03/19 职场文书
民事纠纷协议书
2016/03/23 职场文书
教师学期述职自我鉴定
2019/08/16 职场文书
创业计划书之农家乐
2019/10/09 职场文书
SpringBoot整合Mybatis Generator自动生成代码
2021/08/23 Java/Android
mysql的单列多值存储实例详解
2022/04/05 MySQL
Python写情书? 10行代码展示如何把情书写在她的照片里
2022/04/21 Python