在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中线程问题的简单讲解
Apr 03 Python
pytorch + visdom 处理简单分类问题的示例
Jun 04 Python
解决pandas中读取中文名称的csv文件报错的问题
Jul 04 Python
解决Shell执行python文件,传参空格引起的问题
Oct 30 Python
对python 合并 累加两个dict的实例详解
Jan 21 Python
Python学习笔记之迭代器和生成器用法实例详解
Aug 08 Python
python 并发编程 多路复用IO模型详解
Aug 20 Python
python+rsync精确同步指定格式文件
Aug 29 Python
python用类实现文章敏感词的过滤方法示例
Oct 27 Python
Python函数式编程指南:对生成器全面讲解
Nov 19 Python
基于Python中isfile函数和isdir函数使用详解
Nov 29 Python
如何使用Pytorch搭建模型
Oct 26 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
为PHP5.4开启Zend OPCode缓存
2014/12/26 PHP
推荐一本PHP程序猿都应该拜读的书
2014/12/31 PHP
WordPress中用于获取搜索表单的PHP函数使用解析
2016/01/05 PHP
CodeIgniter扩展核心类实例详解
2016/01/20 PHP
PHP序列化的四种实现方法与横向对比
2018/11/29 PHP
PHP读取目录树的实现方法分析
2019/03/22 PHP
PHP ElasticSearch做搜索实例讲解
2020/02/05 PHP
表单项的name命名为submit、reset引起的问题
2007/12/22 Javascript
教你如何在 Javascript 文件里使用 .Net MVC Razor 语法
2014/07/23 Javascript
js实现从中间开始往上下展开网页窗口的方法
2015/03/02 Javascript
js获取新浪天气接口的实现代码
2016/06/06 Javascript
详解vue-router 2.0 常用基础知识点之router.push()
2017/05/10 Javascript
Angular2关于@angular/cli默认端口号配置的问题
2017/07/15 Javascript
nodejs项目windows下开机自启动的方法
2017/11/22 NodeJs
JS实现的贪吃蛇游戏完整实例
2019/01/18 Javascript
利用angular自动编译andriod APK的绕坑经历分享
2019/03/08 Javascript
JS严格模式原理与用法实例分析
2020/04/27 Javascript
Ant Design的Table组件去除
2020/10/24 Javascript
[01:04:06]DOTA2上海特级锦标赛A组资格赛#2 Secret VS EHOME第一局
2016/02/26 DOTA
Python获取DLL和EXE文件版本号的方法
2015/03/10 Python
python实现在字符串中查找子字符串的方法
2015/07/11 Python
在Python中使用正则表达式的方法
2015/08/13 Python
Python3爬虫爬取英雄联盟高清桌面壁纸功能示例【基于Scrapy框架】
2018/12/05 Python
在python中将字符串转为json对象并取值的方法
2018/12/31 Python
python 叠加等边三角形的绘制的实现
2019/08/14 Python
Django如何继承AbstractUser扩展字段
2020/11/27 Python
python实现猜拳游戏项目
2020/11/30 Python
存储过程和sql语句的优缺点
2014/07/02 面试题
税务干部鉴定材料
2014/02/11 职场文书
初级会计求职信范文
2014/02/15 职场文书
党员干部反四风民主生活会对照检查材料思想汇报
2014/10/12 职场文书
有限公司股东合作协议书
2014/10/29 职场文书
乡镇2014法制宣传日活动总结
2014/11/01 职场文书
导游欢送词
2015/01/31 职场文书
陕西导游词
2015/02/04 职场文书
2015年数学教研组工作总结
2015/05/23 职场文书