在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判断IP地址合法性的方法实例
Mar 13 Python
Python中的CURL PycURL使用例子
Jun 01 Python
给Python初学者的一些编程技巧
Apr 03 Python
Python制作词云的方法
Jan 03 Python
Python通过调用有道翻译api实现翻译功能示例
Jul 19 Python
对Python实现累加函数的方法详解
Jan 23 Python
一文了解Python并发编程的工程实现方法
May 31 Python
python实现车牌识别的示例代码
Aug 05 Python
numpy.linalg.eig() 计算矩阵特征向量方式
Nov 29 Python
Python模块的制作方法实例分析
Dec 21 Python
浅谈Python中的函数(def)及参数传递操作
May 25 Python
教你使用pyinstaller打包Python教程
May 27 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/12/22 PHP
php中yar框架实例用法讲解
2020/12/27 PHP
显示、隐藏密码
2006/07/01 Javascript
js 蒙版进度条(结合图片)
2010/03/10 Javascript
在javascript中执行任意html代码的方法示例解读
2013/12/25 Javascript
jQuery元素选择器用法实例
2014/12/23 Javascript
在AngularJS中如何使用谷歌地图把当前位置显示出来
2016/01/25 Javascript
BootStrap实现树形目录组件代码详解
2016/06/21 Javascript
JavaScript基础知识点归纳(推荐)
2016/07/09 Javascript
15款最好的Bootstrap在线编辑器
2016/08/03 Javascript
基于javascript实现最简单选项卡切换
2017/02/01 Javascript
jQuery插件HighCharts实现的2D堆条状图效果示例【附demo源码下载】
2017/03/14 Javascript
JavaScript数组_动力节点Java学院整理
2017/06/26 Javascript
vue.js项目中实用的小技巧汇总
2017/11/29 Javascript
jQuery-ui插件sortable实现自由拖动排序
2018/12/01 jQuery
微信小程序-form表单提交代码实例
2019/04/29 Javascript
JavaScript命名空间模式实例详解
2019/06/20 Javascript
解决Vue打包后访问图片/图标不显示的问题
2019/07/25 Javascript
vue 集成 vis-network 实现网络拓扑图的方法
2019/08/07 Javascript
node静态服务器实现静态读取文件或文件夹
2019/12/03 Javascript
Vue路由权限控制解析
2020/11/09 Javascript
[15:07]lgd_OG_m2_BP
2019/09/10 DOTA
异步任务队列Celery在Django中的使用方法
2018/06/07 Python
解决Python中定时任务线程无法自动退出的问题
2019/02/18 Python
使用tensorboard可视化loss和acc的实例
2020/01/21 Python
python regex库实例用法总结
2021/01/03 Python
Reformation官网:美国女装品牌
2018/09/14 全球购物
GE设备配件:GE Appliance Parts(家电零件、配件和滤水器)
2018/11/28 全球购物
高中毕业生生活的自我评价
2013/12/08 职场文书
励志演讲稿600字
2014/08/21 职场文书
2014年小学体育工作总结
2014/12/11 职场文书
微信搭讪开场白
2015/05/28 职场文书
中学总务处工作总结
2015/08/12 职场文书
56句经典英文座右铭
2019/08/09 职场文书
python 提取html文本的方法
2021/05/20 Python
python实现简单的三子棋游戏
2022/04/28 Python