在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标准库之多进程(multiprocessing包)介绍
Nov 25 Python
Python实现的检测网站挂马程序
Nov 30 Python
Python中的特殊语法:filter、map、reduce、lambda介绍
Apr 14 Python
如何使用 Pylint 来规范 Python 代码风格(来自IBM)
Apr 06 Python
Python实现接受任意个数参数的函数方法
Apr 21 Python
python实现数据导出到excel的示例--普通格式
May 03 Python
使用Python的SymPy库解决数学运算问题的方法
Mar 27 Python
一行Python代码过滤标点符号等特殊字符
Aug 12 Python
python实现对服务器脚本敏感信息的加密解密功能
Aug 13 Python
numpy 声明空数组详解
Dec 05 Python
python-docx文件定位读取过程(尝试替换)
Feb 13 Python
pycharm设置默认的UTF-8编码模式的方法详解
Jun 01 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
DEDE采集大师官方留后门的删除办法
2011/01/08 PHP
php中in_array函数用法分析
2014/11/15 PHP
Laravel 5 框架入门(三)
2015/04/09 PHP
详解PHP的Yii框架的运行机制及其路由功能
2016/03/17 PHP
PHP中类的继承和用法实例分析
2016/05/24 PHP
js特效,页面下雪的小例子
2013/06/17 Javascript
javascript dom追加内容实现示例
2013/09/21 Javascript
动态显示可输入的字数提示还可以输入的字数
2014/04/01 Javascript
JavaScript对数组进行随机重排的方法
2015/07/22 Javascript
JavaScript节点及列表操作实例小结
2015/08/05 Javascript
JS中使用apply、bind实现为函数或者类传入动态个数的参数
2016/04/26 Javascript
Html5 js实现手风琴效果
2020/04/17 Javascript
webpack+vue2构建vue项目骨架的方法
2018/01/09 Javascript
关于NodeJS中的循环引用详解
2019/07/23 NodeJs
vue自定义正在加载动画的例子
2019/11/14 Javascript
js实现秒表计时器
2019/12/16 Javascript
Node.js API详解之 assert模块用法实例分析
2020/05/26 Javascript
[03:52]DOTA2英雄基础教程 酒仙
2013/12/23 DOTA
python制作小说爬虫实录
2017/08/14 Python
pandas 数据归一化以及行删除例程的方法
2018/11/10 Python
Python 实现大整数乘法算法的示例代码
2019/09/17 Python
python并发爬虫实用工具tomorrow实用解析
2019/09/25 Python
python实现超市商品销售管理系统
2019/11/22 Python
如何利用Python 进行边缘检测
2020/10/14 Python
Python为何不支持switch语句原理详解
2020/10/21 Python
阻止移动设备(手机、pad)浏览器双击放大网页的方法
2014/06/03 HTML / CSS
MAC彩妆澳洲官网:M·A·C AU
2021/01/17 全球购物
物业保安主管岗位职责
2013/12/25 职场文书
人事助理自荐信
2014/02/02 职场文书
治庸问责心得体会
2014/09/12 职场文书
2014领导班子正风肃纪思想汇报
2014/09/18 职场文书
入党函调证明材料
2014/12/24 职场文书
收银员岗位职责范本
2015/04/07 职场文书
呼兰河传读书笔记
2015/06/30 职场文书
幼儿园师德师风心得体会
2016/01/12 职场文书
python tkinter实现定时关机
2021/04/21 Python