python loop until_python3-asyncio 学习笔记 3 -- run_until_complete
在笔记1中追踪了 call_soon这中调用方式是如何运行的,这次看一看 run_until_complete是怎么工作的.
还是由一个简单的例子开始:
import asyncio
async def hi(loop):
print("Hello World")
loop = asyncio.get_event_loop()
# Blocking call which returns when the display_date() coroutine is done
loop.run_until_complete(hi(loop))
loop.stop()
loop.close()
一开始还是通过asyncio.get_event_loop()得到事件循环, 之后调用了 run_until_complete,而调用的参数是一个 async 修饰过的函数的返回值,
async def hi():
print("Hello World")
a = hi()
print(type(a))
#Out[3]: coroutine
可以通过简单的调用 type 来得到它的返回类型, 至于到底是什么, 可参见 asyncio.coroutine , 如果非要追究到底,其实在cpython的源码中是有写的,
typedef struct {
/* The gi_ prefix is intended to remind of generator-iterator. */
_PyGenObject_HEAD(gi)
} PyGenObject;
typedef struct {
_PyGenObject_HEAD(cr)
} PyCoroObject;
可以看出 coroutine和 生成器 其实是一个根源.因此通过 dir() 得到的结果也是很相似的.
回到 run_until_complete, 我们将一个 coroutine 传给它,之后发生了什么?
def run_until_complete(self, future):
self._check_closed()
future = tasks.ensure_future(future, loop=self)
future.add_done_callback(_run_until_complete_cb)
try:
self.run_forever()
except:
...
future.remove_done_callback(_run_until_complete_cb)
if not future.done():
raise RuntimeError('Event loop stopped before Future completed.')
return future.result()
去点注释和非关键部分就如上所示.可以看到传进去的 coroutine 又传给了 tasks.ensure_future, 继续追踪,发现其实这个 coroutine传到了 tasks.Task中用来构造 Task 对象了.而在构造 Task 对象之后或者准确的说的是构造的末尾, 通过 self._loop.call_soon(self._step)调用了 Task 对象的 _step 方法. 在其中,通过
result = coro.send(None)
开始执行我们传递进去的 coroutine, 由于出自生成器, 所以 send 的调用作用是一致的, 都是执行到 挂起 的位置返回. 比如下面简单的示例,
async def hi():
print("Hello World")
a = hi()
try:
result = a.send(None)
except StopIteration as exc:
print(exc.value)
#输出结果如下
Hello World
None
同理,这里的 result = coro.send(None) 也是如此, 如果触发了 StopIteration, 说明 coroutine 已经运行完了.如果没有呢, 比如在 coroutine中遇到了 挂起 呢?
blocking = getattr(result, '_asyncio_future_blocking', None)
首先会检查是否阻塞.先说没有阻塞即 blocking is None 的情况:
情况一 inspect.isgenerator(result) result是一个生成器:
这种在新的语法中是不允许的, 及在 coroutine中不允许再使用yield, 而应使用 yield from
情况二 result is None:
这种是 coroutine返回了一次迭代但是并没有执行完, 这种可以看到是直接通过
self._loop.call_soon(self._step)进行了下一次迭代.
剩余情况 :
错误情况,直接抛出异常
那blocking 非 None的情况呢? 首先要知道什么 coroutine会返回 blocking is not None.
我们可以简单的从字面看出, coroutine 中需要有阻塞才可以. 可以简单的尝试三个情景:
import asyncio
async def no_block_no_return():
print("haha")
async def no_block_with_return():
print("haha")
return 1
async def with_block():
await asyncio.sleep(1.0)
print("haha")
return 1
first = no_block_no_return()
second = no_block_with_return()
third = with_block()
try:
first_result = first.send(None)
except StopIteration as exc:
print(exc.value)
try:
second_result = second.send(None)
except StopIteration as exc:
print(exc.value)
try:
third_result = third.send(None)
except StopIteration as exc:
print(exc.value)
'''
result:
haha
None
haha
1
'''
再检查,发现只有 third_result 是有定义的, 而且是 _asyncio.Future, 这时检查 blocking
assert getattr(third_result, '_asyncio_future_blocking', None)
会发现这就是我们要找的 blocking is not None.也就是在 coroutine中触发另一个coroutine.
这个 _asyncio.Future是c实现的 Future ,可以在 CPython 源码的 Modules/_asynciomodule.c中找到相关的定义, 其实和 asyncio.Future是类似的.所以我们这里参考python实现的 Future.
那么 await到底发生了什么?
其实要理解await到底做了啥也不难.前面已经说过,coroutine 和生成器类似.比如下面的代码:
async def with_block():
await asyncio.sleep(1.0)
print("haha")
return 1
翻译成没有await关键字的python代码就成了:
def fake_with_block():
#asyncio.sleep 示意如下
loop = asyncio.get_event_loop()
future = loop.create_future()
h = future._loop.call_later(
1.0, futures._set_result_unless_cancelled, future,None)
def _await():
while not future.done():
yield future
yield from _await()
#以上就是await的不完全等价的一个示意,注:只适用于此特殊情景,不能套用
print("haha")
return 1
也就是await后面的(同一行)语句(表达式)悄悄的执行了并和生成器似的返回了,不过返回了一个future对象.
所以在blocking is not None 的语块内可以看到:
result.add_done_callback(self._wakeup)
也就是添加了future结束后的操作.那怎么知道 await后面的(同一行)语句(表达式)运行完了呢?于是asyncio.future中有了set_result的方法.通过set_result来表明future执行完了并执行绑定的call_back.而这里的sleep是通过call_later延迟调用的方式执行set_result.
于是所有的操作就都合并到了loop._run_once中了.这样就完整的循环起来了.
可await后面(后面的行)还有语句要执行啊?添加的那个call_back,就是负责await部分完成了后面怎么运行的.
def _wakeup(self, future):
try:
future.result()
except Exception as exc:
self._step(exc)
else:
self._step()
self = None
可以看到,await执行完,如果没有异常,还是继续_step也就是coro.send(None),也就是继续await后面(后面的行)的内容,这样一个coro就能完整的运行了.
至此,future = tasks.ensure_future(future, loop=self)就剖析完了.后面的
future.add_done_callback(_run_until_complete_cb)
try:
self.run_forever()
except:
...
future.remove_done_callback(_run_until_complete_cb)
就是异常处理和开始事件循环,在笔记1中已经提过了就不再赘余.
python loop until_python3-asyncio 学习笔记 3 -- run_until_complete相关推荐
- python loop call soon_python3-asyncio 学习笔记 1 -- call_soon
最近在学习python3 的 asyncio, 特将学习笔记记录于此. 先来个简单的例子: import asyncio def hello_world(loop): print('Hello Wor ...
- 36篇博文带你学完opencv :python+opencv进阶版学习笔记目录
基础版学习笔记传送门 36篇博文带你学完opencv :python3+opencv学习笔记汇总目录(基础版) 进阶版笔记 项目 opencv进阶学习笔记1: 调用摄像头用法大全(打开摄像头,打开摄像 ...
- Python中索引的学习笔记
1 前言 今天在学习FaceBoxes- 看到一个比较奇怪的代码,"order = scores.argsort()[::-1][:args.top_k]",不太懂这个" ...
- Python地理做图——学习笔记
Python地理做图--学习笔记 GMT 绘制海岸线 绘制地形并叠加海岸线 地理信息数据格式在线转换网址 适用OSGEO4w可以实现tif转nc,转grd 绘制grd和nc 除了投影方式-X, gmt ...
- 基于python的数字图像处理--学习笔记(三)
基于python的数字图像处理--学习笔记(三) 前言 一.灰度拉伸 二.幂律(伽马)变换 三.对数变换 前言 进入冈萨雷斯的第三章内容,并用python实现功能.我更改了代码源,之前找到太烂了,代码 ...
- Python第三方库pygame学习笔记(一)
Pygame Python最经典的2D游戏开发第三方库,也支持3D游戏开发 Pygame适合用于游戏逻辑验证.游戏入门及系统演示验证 Pygame是一种游戏开发引擎,基本逻辑具有参考价值 pygame ...
- python气象数据可视化学习笔记6——利用python地图库cnmaps绘制地图填色图并白化
文章目录 1. 效果图 2. cnmaps简介及安装 2.1 写在前面 2.2 cnmaps简介和安装 3. 导入库 4. 定义绘图函数 4.1 使用get_adm_maps返回地图边界 4.2 ax ...
- Python快速编程入门#学习笔记01# |第一章 :Python基础知识 (Python发展历程、常见的开发工具、import模块导入)
全文目录 ==先导知识== 1 认识Python 1.1.1 Python的发展历程 1.1.2 Python语言的特点 2. Python解释器的安装与Python程序运行 1.2.1 安装Pyth ...
- Python+cplex运筹优化学习笔记(三)-营养膳食选择
Python+cplex运筹优化学习笔记(三)-营养膳食选择 前言 首先呢,说明一下,本文只是自己在学习过程中运用到的例子,然后规整总结一下,随便写写自己所做的一些笔记.小白学习,有不对的地方还望大家 ...
- 全国计算机等级考试二级Python精品题库学习笔记1
全国计算机等级考试二级Python精品题库学习笔记1 精品试卷01 精品试卷01程序题 基本操作题 2:随机验证码 基本操作题 3:比赛成绩计算 Turtle 绘图题:同心圆 简单应用题 2:员工工资 ...
最新文章
- 以太坊区块链同步_以太坊69:如何在10分钟内建立完全同步的区块链节点
- 云端TensorFlow读取数据IO的高效方式
- golang 开源代理
- cad卸载_怎么把CAD卸载干净,老司机来教你
- 深入解读:获Forrester大数据能力高评价的阿里云DataWorks思路与能力
- 招聘数下降71%!程序员:你的努力正在毁掉自己!
- 北京大学计算机学院周磊,马秀莉-北京大学信息科学技术学院
- 数据预处理和数据特征工程
- python所有第三方库_自动更新Python所有第三方库
- Windows开始菜单快捷方式位置(磁贴)
- 智能陈桥五笔7.8试用编号是多少_如何设计和编写软件测试用例
- Java IO——字节流和字符流详解区别对比
- android mov转mp4格式转换,如何在线将MOV文件转换成MP4文件?
- oracle导入excel乱码,Oracle导出的文件为什么用Excel打开是乱码?
- 分享:淘宝客完全开源程序。
- 高颜值挂脖式运动蓝牙耳机盘点,五款3D环绕高音质蓝牙耳机测评分享
- ElementUI全局配置message的弹窗时间
- 【毕业设计】基于STM32及OpenMV的云台追踪装置
- 【渝粤教育】21秋期末考试马克思主义基本原理概论(A)10882k1
- 甲骨文大数据利器:内存数据库和一体机
热门文章
- 12v小型电机型号大全_电机型号参数大全,再不怕看不懂型号了
- linux shell调用c 程序设计,linux – 在bash -c中设置变量
- Intouch使用SIDirect OIServer 连接西门子PLC S7-300
- Pytorch使用Tensorboard记录loss曲线 (Tensorboard学习二)
- python转str类型的列表为list格式
- django新建utils文件夹与导入方法
- java exec source报错_Mac 下maven路径报错的坑
- idea设置关键字颜色_IDEA字体颜色快速导入辅助工具设置
- linux配置php mysql_Linux下LAMP(Apache+PHP+MySql)环境配置
- linux内存管理机制