推文:玩转 Python 3.5 的 await/async

首先看正常的两个函数之间的执行

def func1():
print("func1 start")
print("func1 end") def func2():
print("func2 start")
print("func2 a")
print("func2 b")
print("func2 c")
print("func2 end") func1()
func2()
func1 start
func1 end
func2 start
func2 a
func2 b
func2 c
func2 end

无法实现两个函数之间的交互。

将这两个函数设置为协程,加上async关键字

async def func1():
print("func1 start")
print("func1 end") async def func2():
print("func2 start")
print("func2 a")
print("func2 b")
print("func2 c")
print("func2 end") f1 = func1()
f2 = func2()
print(f1,f2)
<coroutine object func1 at 0x000000000084C468> <coroutine object func2 at 0x000000000084CD58>
sys:: RuntimeWarning: coroutine 'func1' was never awaited  #警告信息
sys:: RuntimeWarning: coroutine 'func2' was never awaited #上面不再只是函数,而变为协程对象,协程在调用时,不会被执行

那么,为什么要有一个协程对象?代码到底如何执行?

关键之处是协程确实是与 Python 的生成器非常相似,也都有一个 send 方法。我们可以通过调用 send 方法来启动一个协程的执行。

f1 = func1()
f2 = func2() try:
print('f1.send')
f1.send(None)
except StopIteration as e:  #这里也是需要去捕获StopIteration方法
pass try:
print('f1.send')
f2.send(None)
except StopIteration as e:
pass

StopIteration 异常是一种标记生成器(或者像这里的协程)执行结束的机制。虽然这是一个异常,但是确实是我们期望的!我们可以用适当的 try-catch 代码将其包起来,这样就可以避免错误提示。

上面虽然将两个协程都执行起来了,但是并没有做到交替执行,和最初的并无不同,而且似乎更加麻烦

协程与线程相似的地方是多个线程之间也可以交替执行,不过与线程不同之处在于协程之间的切换是显式的,而线程是隐式的(大多数情况下是更好的方式)。所以我们需要加入显式切换的代码。

我们可能根据生成器或者协程gevent的使用,而去推测这种方案:(是错误的)

async def func1():
print("func1 start")
yield
print("func1 end")

不允许在本地协程函数中使用yield,但是作为替换,我们可以使用到await 表达式来暂停协程的执行。注意await _something_,这里的_something_代表的是基于生成器的协程对象,或者一个特殊的类似 Future 的对象。

下面使用一个基于生成器的协程函数

import types

@types.coroutine
def switch():
yield async def func1():
print("func1 start")
await switch()
print("func1 end") async def func2():
print("func2 start")
print("func2 a")
print("func2 b")
print("func2 c")
print("func2 end") f1 = func1()
f2 = func2() try:
f1.send(None)
except StopIteration as e:
pass try:
f2.send(None)
except StopIteration as e:
pass
func1 start
func2 start
func2 a
func2 b
func2 c
func2 end

注意上面的输出:只是执行了函数的转换,有func1转换到func2,并没有再回到func1中。那么如何让其在回到func1中呢。

我们可以基于生成器一样再次对func1协程使用send方法,再次激活yield向下执行

import types

@types.coroutine
def switch():
yield async def func1():
print("func1 start")
await switch()
print("func1 end") async def func2():
print("func2 start")
print("func2 a")
print("func2 b")
print("func2 c")
print("func2 end") f1 = func1()
f2 = func2() try:
f1.send(None)
except StopIteration as e:
pass try:
f2.send(None)
except StopIteration as e:
pass try:
f1.send(None)
except StopIteration as e:
pass
func1 start
func2 start
func2 a
func2 b
func2 c
func2 end
func1 end

上面可以实现两个函数交替一次,回到原协程中。但是我们更加希望连续不断的调用send驱动不同的协程去执行,直到send抛出 StopIteration 异常。

为此我们

新建一个函数,这个函数传入一个协程列表,函数执行这些协程直到全部结束。我们现在要做的就是调用这个函数。

import types

@types.coroutine
def switch():
yield async def func1():
print("func1 start")
await switch()
print("func1 e")
await switch()
print("func1 end") async def func2():
print("func2 start")
print("func2 a")
await switch()
print("func2 b")
print("func2 c")
await switch()
print("func2 end") def run(task_list):
coro_list = list(task_list) while coro_list:
for coro in list(coro_list):
try:
coro.send(None)
except StopIteration:
coro_list.remove(coro) f1 = func1()
f2 = func2() run([f1,f2])

python---await/async关键字的更多相关文章

  1. 对于Linq关键字和await,async异步关键字的扩展使用

    最近在看neuecc大佬写的一些库:https://neuecc.medium.com/,其中对await,async以及linq一些关键字实现了自定义化使用, 使其不需要引用对应命名空间,不需要多线 ...

  2. javascript异步编程的前世今生,从onclick到await/async

    javascript与异步编程 为了避免资源管理等复杂性的问题, javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是为 ...

  3. 5分种让你了解javascript异步编程的前世今生,从onclick到await/async

      javascript与异步编程 为了避免资源管理等复杂性的问题,javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是 ...

  4. await和async关键字来写异步程序

    await和async关键字出现于.Net5.0,方便写异步程序. 例子: public class MyClass { public MyClass() { DisplayValue(); //这里 ...

  5. C#异步编程のawait和async关键字来写异步程序

    一.await和async关键字 .Net平台不断推出了新的异步编程模型,在.net4.5中加入了关键字await和async,顾名思义,await是指方法执行可等待,即可挂起直到有结果(不是必须立即 ...

  6. C#~异步编程续~.net4.5主推的await&async应用

    返回目录 之前写过两篇关于异步编程的文章,详细可以进入C#~异步编程和C#~异步编程在项目中的使用 .net的各个版本都有自己主推的技术,像.NET1.1中的委托,.NET2.0中的泛型,.NET3. ...

  7. C#~异步编程续~.net4.5主推的await&async应用(转)

    之前写过两篇关于异步编程的文章,详细可以进入C#~异步编程和C#~异步编程在项目中的使用 .net的各个版本都有自己主推的技术,像.NET1.1中的委托,.NET2.0中的泛型,.NET3.0中的Li ...

  8. Silverlight项目笔记1:UI控件与布局、MVVM、数据绑定、await/async、Linq查询、WCF RIA Services、序列化、委托与事件

    最近从技术支持转到开发岗,做Silverlight部分的开发,用的Prism+MVVM,框架由同事搭好,目前做的主要是功能实现,用到了一些东西,侧重于如何使用,总结如下 1.UI控件与布局 常用的主要 ...

  9. 如何避免 await/async 地狱

    原文地址:How to escape async/await hell 译文出自:夜色镇歌的个人博客 async/await 把我们从回调地狱中解救了出来,但是如果滥用就会掉进 async/await ...

随机推荐

  1. struts2封装请求参数

    利用struts2框架进行将页面请求的参数封装有三种方法 第一种(不推荐) 就是动作类和bean中结合在一起,这样方法比较简单,但是很混乱. 代码: package com.example.actio ...

  2. spring冲刺第七天

    昨天进行地图和人物的代码整合,有所缺陷. 今天使人物成功的在地图上运动,并设计炸弹爆炸效果. 遇到的问题:炸弹不会吧人物炸死,只会炸没砖块.

  3. Task 4 求数组的连续子数组的最大和(团队合作)

    小组成员:李敏.刘子晗 1.设计思想:由于已经做过这个题目,只要对之前的程序加上相应的测试和约束即可.我们两个人一起商议后,决定了程序的主框架和并列出了最终可以实现的功能.先要定义数组长度和上下限的变 ...

  4. echart 插件实现全国地图

    最近的项目要用到一个能展现全国地图的功能,并且全国各个省份显示的颜色不同,点击省份后会返回省份名称.经过反复的查找最终确定了echart这个插件,最后的成果还不错,在这里写下来希望对大家有所帮助.话不 ...

  5. Leetcode题库——8.字符串转为整数【##】

    @author: ZZQ @software: PyCharm @file: myAtoi.py @time: 2018/9/20 20:54 要求:实现 atoi,将字符串转为整数. 1)根据需要丢 ...

  6. 《TCP/IP 详解 卷1:协议》第 8 章:Internet 控制报文协议

    路由器是 Internet 的重要组成部分,严密监视 Internet 的操作.IP 协议未给发送失败的 IP 数据包提供一种错误处理,也没有给端系统提供直接的方法来发现错误.为了解决这一不足之处,I ...

  7. Akka系列---什么是Actor

    本文已.Net语法为主,同时写有Scala及Java实现代码 严肃的说,演员是一个广泛的概念,作为外行人我对Actor 模型的定义: Actor是一个系统中参与者的虚拟人物,Actor与Actor之间 ...

  8. 转 彻底理解js中的&&和||

    javascript中,&&和||的用法比较神奇,经常用在对象上,例如a || b,如果a不存在,则返回b.a && b,如果a存在,则返回b,否则返回a. 光这样看, ...

  9. VR论文调研

    IEEE VR 2018 1.Avatars and Virtual Humans--人物和虚拟人物 2.Augmented Reality--增强现实 3.Body and Mind--人体和思想( ...

  10. Java开发中的23种设计模式详解(转载)

    前学习过一段时间的设计模式,总是感觉学习的不够清楚.现在再重新复习一下,原文地址:https://blog.csdn.net/doymm2008/article/details/13288067 一. ...