在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使用点操作符访问字典(dict)数据的方法
Mar 16 Python
python连接mysql实例分享
Oct 09 Python
Python基于matplotlib绘制栈式直方图的方法示例
Aug 09 Python
django使用xlwt导出excel文件实例代码
Feb 06 Python
对numpy中布尔型数组的处理方法详解
Apr 17 Python
详解Python做一个名片管理系统
Mar 14 Python
Python OS模块实例详解
Apr 15 Python
Python Django 封装分页成通用的模块详解
Aug 21 Python
浅谈numpy中函数resize与reshape,ravel与flatten的区别
Jun 18 Python
Pycharm连接gitlab实现过程图解
Sep 01 Python
python获取linux系统信息的三种方法
Oct 14 Python
python 实现"神经衰弱"翻牌游戏
Nov 09 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删除数组中特定元素的两种方法
2013/07/02 PHP
浅谈PHP定义命令空间的几个注意点(推荐)
2016/10/29 PHP
Yii2汉字转拼音类的实例代码
2017/04/18 PHP
PHP获取日期对应星期、一周日期、星期开始与结束日期的方法
2018/06/22 PHP
PHP使用Session实现上传进度功能详解
2019/08/06 PHP
调用js时ie6和ie7,ff的区别
2009/08/19 Javascript
javascript中将Object转换为String函数代码 (json str)
2012/04/29 Javascript
javascript日期格式化示例分享
2014/03/05 Javascript
jquery1.10给新增元素绑定事件的方法
2014/03/06 Javascript
原生js仿jq判断当前浏览器是否为ie,精确到ie6~8
2014/08/30 Javascript
javascript操作Cookie(设置、读取、删除)方法详解
2015/03/18 Javascript
jQuery实现的跨容器无缝拖动效果代码
2016/06/21 Javascript
JS命令模式例子之菜单程序
2016/10/10 Javascript
Reactjs实现通用分页组件的实例代码
2017/01/19 Javascript
xmlplus组件设计系列之按钮(2)
2017/04/26 Javascript
Node.js如何使用Diffie-Hellman密钥交换算法详解
2017/09/05 Javascript
Layui实现数据表格中鼠标悬浮图片放大效果,离开时恢复原图的方法
2019/09/11 Javascript
原生js实现下拉选项卡
2019/11/27 Javascript
js实现随机圆与矩形功能
2020/10/29 Javascript
在vue中通过render函数给子组件设置ref操作
2020/11/17 Vue.js
Python中@property的理解和使用示例
2019/06/11 Python
django Admin文档生成器使用详解
2019/07/22 Python
Python PIL图片添加字体的例子
2019/08/22 Python
python支付宝支付示例详解
2019/08/22 Python
PyInstaller将Python文件打包为exe后如何反编译(破解源码)以及防止反编译
2020/04/15 Python
python 基于opencv操作摄像头
2020/12/24 Python
英国知名衬衫品牌美国网站:Charles Tyrwhitt美国
2016/08/28 全球购物
全球最大的中文旅行网站:去哪儿网
2017/11/16 全球购物
化学相关工作求职信
2013/10/02 职场文书
初入社会应届生求职信
2013/11/18 职场文书
授权委托书格式
2014/07/31 职场文书
防灾减灾宣传标语
2014/10/07 职场文书
2015年暑期见闻
2015/07/14 职场文书
2016年庆祝六一儿童节活动总结
2016/04/06 职场文书
新手初学Java List 接口
2021/07/07 Java/Android
mysql查看表结构的三种方法总结
2022/07/07 MySQL