在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 相关文章推荐
rhythmbox中文名乱码问题解决方法
Sep 06 Python
Python 获取新浪微博的最新公共微博实例分享
Jul 03 Python
解决Mac安装scrapy失败的问题
Jun 13 Python
python异步存储数据详解
Mar 19 Python
Python3网络爬虫中的requests高级用法详解
Jun 18 Python
Python selenium的基本使用方法分析
Dec 21 Python
python ubplot使用方法解析
Jan 10 Python
基于Tensorflow:CPU性能分析
Feb 10 Python
Python操作word文档插入图片和表格的实例演示
Oct 25 Python
如何创建一个Flask项目并进行简单配置
Nov 18 Python
python uuid生成唯一id或str的最简单案例
Jan 13 Python
Python机器学习算法之决策树算法的实现与优缺点
May 13 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中常用编辑器推荐
2007/01/02 PHP
PHP安全防范技巧分享
2011/11/03 PHP
php中限制ip段访问、禁止ip提交表单的代码分享
2014/08/22 PHP
PHP中使用GD库创建圆形饼图的例子
2014/11/19 PHP
PHP实现多维数组转字符串和多维数组转一维数组的方法
2015/08/08 PHP
PHP实现的同步推荐操作API接口案例分析
2016/11/30 PHP
JSON序列化与解析原生JS方法且IE6和chrome测试通过
2013/09/05 Javascript
js实现点小图看大图效果的思路及示例代码
2013/10/28 Javascript
JavaScript伸缩的菜单简单示例
2013/12/03 Javascript
javascript面向对象之共享成员属性与方法及prototype关键字用法
2015/01/13 Javascript
Javascript实现的SHA-256加密算法完整实例
2016/02/02 Javascript
微信公众号 客服接口的开发实例详解
2016/09/28 Javascript
js+SVG实现动态时钟效果
2018/07/14 Javascript
vue项目前端错误收集之sentry教程详解
2019/05/27 Javascript
在vue中使用jsx语法的使用方法
2019/09/30 Javascript
[26:24]完美副总裁、DOTA2负责人蔡玮专访:电竞如人生
2014/09/11 DOTA
python实现通过代理服务器访问远程url的方法
2015/04/29 Python
在Mac OS上部署Nginx和FastCGI以及Flask框架的教程
2015/05/02 Python
Python实现FTP上传文件或文件夹实例(递归)
2017/01/16 Python
Python数据结构之栈、队列的实现代码分享
2017/12/04 Python
Python3使用turtle绘制超立方体图形示例
2018/06/19 Python
如何通过python画loss曲线的方法
2019/06/26 Python
python Matplotlib底图中鼠标滑过显示隐藏内容的实例代码
2019/07/31 Python
Python字典添加,删除,查询等相关操作方法详解
2020/02/07 Python
Python表达式的优先级详解
2020/02/18 Python
浅谈在django中使用filter()(即对QuerySet操作)时踩的坑
2020/03/31 Python
python 爬虫请求模块requests详解
2020/12/04 Python
java关于string最常出现的面试题整理
2021/01/18 Python
Harrods美国:英国最大的百货公司
2018/11/04 全球购物
中学生自我鉴定
2014/02/04 职场文书
采购意向书范本
2014/03/31 职场文书
原料仓管员岗位职责
2014/04/12 职场文书
意向协议书范本
2014/04/23 职场文书
酒店财务总监岗位职责
2015/04/03 职场文书
《圆的周长》教学反思
2016/02/17 职场文书
javascript遍历对象的五种方式实例代码
2021/10/24 Javascript