在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实现博客文章爬虫示例
Feb 26 Python
简单学习Python time模块
Apr 29 Python
利用Python自带PIL库扩展图片大小给图片加文字描述的方法示例
Aug 08 Python
Python设计模式之MVC模式简单示例
Jan 10 Python
python实现批量图片格式转换
Jun 16 Python
对numpy中二进制格式的数据存储与读取方法详解
Nov 01 Python
Python多进程入门、分布式进程数据共享实例详解
Jun 03 Python
python 叠加等边三角形的绘制的实现
Aug 14 Python
ubuntu 18.04 安装opencv3.4.5的教程(图解)
Nov 04 Python
Python多线程多进程实例对比解析
Mar 12 Python
python文件路径操作方法总结
Dec 21 Python
python批量生成身份证号到Excel的两种方法实例
Jan 14 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日期转时间戳,指定日期转换成时间戳
2012/07/17 PHP
js+php实现静态页面实时调用用户登陆状态的方法
2015/01/04 PHP
JavaScript方法和技巧大全
2006/12/27 Javascript
XENON基于JSON变种
2010/07/27 Javascript
javascript通过class来获取元素实现代码
2013/02/20 Javascript
jQuery prev ~ siblings选择器使用介绍
2013/08/09 Javascript
使用Jquery实现点击文字后变成文本框且可修改
2013/09/21 Javascript
js获取当前路径的简单示例代码
2014/01/08 Javascript
JavaScript获取按钮所在form表单id的方法
2015/04/02 Javascript
Vue指令的钩子函数使用方法
2017/03/20 Javascript
jQuery中map函数的两种方式
2017/04/07 jQuery
详解VueJS应用中管理用户权限
2018/02/02 Javascript
JS实现动态生成html table表格的方法分析
2018/07/11 Javascript
webpack4 + react 搭建多页面应用示例
2018/08/03 Javascript
基于vue-cli3+typescript的tsx开发模板搭建过程分享
2020/02/28 Javascript
[03:36]2014DOTA2 TI小组赛综述 八强诞生进军钥匙球馆
2014/07/15 DOTA
200行自定义python异步非阻塞Web框架
2017/03/15 Python
python OpenCV学习笔记直方图反向投影的实现
2018/02/07 Python
Python3和pyqt5实现控件数据动态显示方式
2019/12/13 Python
Python 自由定制表格的实现示例
2020/03/20 Python
Python 代码调试技巧示例代码
2020/08/11 Python
Python开发入门——迭代的基本使用
2020/09/03 Python
Python+OpenCV图像处理——打印图片属性、设置存储路径、调用摄像头
2020/10/22 Python
Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?
2016/08/18 面试题
大唐面试试题(CPU,UNIX等等)
2012/01/11 面试题
《灯光》教学反思
2014/02/08 职场文书
雏鹰争章活动总结
2014/05/09 职场文书
干部鉴定材料
2014/05/18 职场文书
安全检查汇报材料
2014/12/26 职场文书
2015年乡镇发展党员工作总结
2015/03/31 职场文书
[有人@你]你有一封绿色倡议书,请查收!
2019/07/18 职场文书
导游词之山东孔庙
2019/11/04 职场文书
sqlserver2017共享功能目录路径不可改的解决方法
2021/04/16 SQL Server
浅谈node.js中间件有哪些类型
2021/04/29 Javascript
SQL Server #{}可以防止SQL注入
2022/05/11 SQL Server
PostgreSQL常用字符串分割函数整理汇总
2022/07/07 PostgreSQL