在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代码使其加快作用域内的查找
Mar 30 Python
Python之reload流程实例代码解析
Jan 29 Python
Python中装饰器学习总结
Feb 10 Python
Python学习之Django的管理界面代码示例
Feb 10 Python
Python网络编程使用select实现socket全双工异步通信功能示例
Apr 09 Python
Python查找两个有序列表中位数的方法【基于归并算法】
Apr 20 Python
Flask框架使用DBUtils模块连接数据库操作示例
Jul 20 Python
使用CodeMirror实现Python3在线编辑器的示例代码
Jan 14 Python
python实现五子棋小游戏
Mar 25 Python
Django在admin后台集成TinyMCE富文本编辑器的例子
Aug 09 Python
OpenCV-Python实现人脸磨皮算法
Jun 07 Python
matplotlib如何设置坐标轴刻度的个数及标签的方法总结
Jun 11 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
CodeIgniter 完美解决URL含有中文字符串
2016/05/13 PHP
PHP中Socket连接及读写数据超时问题分析
2016/07/19 PHP
PHP+MySql实现一个简单的留言板
2020/07/19 PHP
JS版网站风格切换实例代码
2008/10/06 Javascript
页面中body onload 和 window.onload 冲突的问题的解决
2009/07/01 Javascript
js 巧妙去除数组中的重复项
2010/01/25 Javascript
javascript中日期转换成时间戳的小例子
2013/03/21 Javascript
导入extjs、jquery 文件时$使用冲突问题解决方法
2014/01/14 Javascript
jQuery 顶部导航跟随滚动条滚动固定浮动在顶部
2014/06/06 Javascript
jQuery Migrate 1.1.0 Released 注意事项
2014/06/14 Javascript
JS实现超炫网页烟花动画效果的方法
2015/03/02 Javascript
BootStrap中Tab页签切换实例代码
2016/05/30 Javascript
AngularJS折叠菜单实现方法示例
2017/05/18 Javascript
React-router 4 按需加载的实现方式及原理详解
2017/05/25 Javascript
React Native 通告消息竖向轮播组件的封装
2020/08/25 Javascript
chosen实现省市区三级联动
2018/08/16 Javascript
Python中的descriptor描述器简明使用指南
2016/06/02 Python
python如何实现反向迭代
2018/03/20 Python
python绘制直线的方法
2018/06/30 Python
Python Datetime模块和Calendar模块用法实例分析
2019/04/15 Python
python调用动态链接库的基本过程详解
2019/06/19 Python
Python使用enumerate获取迭代元素下标
2020/02/03 Python
python如何快速生成时间戳
2020/07/21 Python
Python selenium如何打包静态网页并下载
2020/08/12 Python
使用html5新特性轻松监听任何App自带返回键的示例
2018/03/13 HTML / CSS
迪斯尼假期(欧洲、中东及非洲):Disney Holidays EMEA
2021/02/15 全球购物
NET程序员上机面试题
2015/05/23 面试题
捐书寄语赠言
2014/01/18 职场文书
文员岗位职责范本
2014/03/08 职场文书
2015感人爱情寄语
2015/02/26 职场文书
入党转正申请报告
2015/05/15 职场文书
2015年环保局工作总结
2015/05/22 职场文书
培训后的感想
2015/08/07 职场文书
小学班级管理心得体会
2016/01/07 职场文书
Python操作CSV格式文件的方法大全
2021/07/15 Python
Python四款GUI图形界面库介绍
2022/06/05 Python