在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实现读取目录所有文件的文件名并保存到txt文件代码
Nov 22 Python
Python OS模块常用函数说明
May 23 Python
python实现基本进制转换的方法
Jul 11 Python
Python3安装Pymongo详细步骤
May 26 Python
python用户管理系统
Mar 13 Python
在python中按照特定顺序访问字典的方法详解
Dec 14 Python
python 调用钉钉机器人的方法
Feb 20 Python
python使用Plotly绘图工具绘制柱状图
Apr 01 Python
Django Sitemap 站点地图的实现方法
Apr 29 Python
python3.6+selenium实现操作Frame中的页面元素
Jul 16 Python
Python预测2020高考分数和录取情况
Jul 08 Python
浅谈如何使用python抓取网页中的动态数据实现
Aug 17 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的网址
2006/11/25 PHP
php获取随机数组列表的方法
2014/11/13 PHP
CI框架源码解读之URI.php中_fetch_uri_string()函数用法分析
2016/05/18 PHP
JS验证日期的格式YYYY-mm-dd 具体实现
2013/06/29 Javascript
JS取得绝对路径的实现代码
2015/01/16 Javascript
Windows系统中安装nodejs图文教程
2015/02/28 NodeJs
深入理解JavaScript系列(41):设计模式之模板方法详解
2015/03/04 Javascript
简单解析JavaScript中的__proto__属性
2016/05/10 Javascript
jQuery实现的模拟弹出窗口功能示例
2016/11/24 Javascript
如何解决jQuery EasyUI 已打开Tab重新加载问题
2016/12/19 Javascript
微信小程序模板之分页滑动栏
2017/02/10 Javascript
Vue和Bootstrap的整合思路详解
2017/06/30 Javascript
Vue内容分发slot(全面解析)
2017/08/19 Javascript
150行代码带你实现微信小程序中的数据侦听
2019/05/17 Javascript
微信小程序页面间跳转传参方式总结
2019/06/13 Javascript
Python连接phoenix的方法示例
2017/09/29 Python
Django分页查询并返回jsons数据(中文乱码解决方法)
2018/08/02 Python
详解Python装饰器
2019/03/25 Python
python五子棋游戏的设计与实现
2019/06/18 Python
python搜索包的路径的实现方法
2019/07/19 Python
python的help函数如何使用
2020/06/11 Python
基于python实现计算两组数据P值
2020/07/10 Python
python制作一个简单的gui 数据库查询界面
2020/11/19 Python
医科大学生毕业的自我评价分享
2013/11/12 职场文书
教师的实习鉴定
2013/12/15 职场文书
观看《永远的雷锋》心得体会
2014/03/12 职场文书
给小学生的新年寄语
2014/04/04 职场文书
关爱老人标语
2014/06/21 职场文书
学生不讲诚信检讨书
2014/09/29 职场文书
护理见习报告范文
2014/11/03 职场文书
机关工会工作总结2015
2015/05/26 职场文书
本科毕业答辩开场白
2015/05/27 职场文书
如何利用STAR法则制作留学文书?
2019/08/26 职场文书
导游词之山西关帝庙
2019/11/01 职场文书
GoFrame基于性能测试得知grpool使用场景
2022/06/21 Golang
python 镜像环境搭建总结
2022/09/23 Python