python协程学习笔记

coroutine.png
协程的概念

协程(英文叫作 Coroutine),是一种用户态的轻量级线程。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。线程的执行完全是操作系统控制的,而协程的控制权在于用户,本质是为了能让多组过程能不独自占用完所有资源,在一个线程内交叉执行,达到高并发的目的。

协程的优点
  • 极高的执行效率,因为无需系统内核的上下文切换,减小开销;
  • 无需原子操作锁定及同步的开销,不用担心资源共享的问题;
协程的用法

Python 中实现协程的库是asyncio ,通过async def来定义一个协程函数,通过await来执行一个协程对象。

  • event_loop事件循环:程序开启一个无限循环,把一些函数注册到这个事件循环上,当满足条件发生的时候,就会调用相应的协程函数。
  • coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。
  • task任务:它是对协程对象的进一步封装,包含了任务的各个状态。
  • future:代表将来执行或没有执行的任务,和 task 没有本质区别。
  • async/await :python用于定义协程的关键字,async 定义一个协程,await 用来挂起阻塞方法的执行。
  • 可等待对象 :被关键字 await 标记就表明它是个可等待对象 ,Python 协程属于可等待对象,因此可以在其他协程中被等待。换言而之,一个异步函数不能直接调用另一个异步函数,必须在被调用的异步函数前添加 await关键字。
  • 协程函数与协程对象:协程函数,定义为 async def 的函数;协程对象,通过调用协程函数所返回的对象。

我们只要通过async定义协程,await定义阻塞,然后封装成future的task,放入循环的事件列表中,就等着返回数据。

协程的示例

1. 定义协程函数:

async def do_some_work(x):
    print("waiting:",x)
    # await挂起阻塞, 相当于yield, 通常是耗时操作
    await asyncio.sleep(x)
    return "Done after {}s".format(x)

2.定义回调函数:

# 回调函数,它的唯一参数只能是future
def callback(future):
    print("callback:",future.result())

3.将 coroutine 对象转化为 task 对象:

tasks = []
for i in range(1, 4):
    # 定义多个协程,同时预激活
    coroutine = do_some_work(i)
    task = asyncio.ensure_future(coroutine)
    # 添加回调函数
    task.add_done_callback(callback)
    tasks.append(task)

4.获取事件循环:

loop = asyncio.get_event_loop()

5.异步执行协程:

loop.run_until_complete(asyncio.wait(tasks))

6.关闭事件循环:

loop.close()

完整代码示例:

import time
import asyncio

# async定义协程
async def do_some_work(x):
    print("waiting:",x)
    # await挂起阻塞, 相当于yield, 通常是耗时操作
    await asyncio.sleep(x)
    return "Done after {}s".format(x)

# 回调函数,和yield产出类似功能
def callback(future):
    print("callback:",future.result())

tasks = []
for i in range(1, 4):
    # 定义多个协程,同时预激活
    coroutine = do_some_work(i)
    task = asyncio.ensure_future(coroutine)
    task.add_done_callback(callback)
    tasks.append(task)

# 获取事件循环,把任务协程放在里面,
loop = asyncio.get_event_loop()
try:
    # 异步执行协程,直到所有操作都完成
    loop.run_until_complete(asyncio.wait(tasks))
    for task in tasks:
        print("Task ret:",task.result())
except KeyboardInterrupt as e: # 协程任务的状态控制
    print(asyncio.Task.all_tasks())
    for task in asyncio.Task.all_tasks():
        print(task.cancel())
    loop.stop()
    loop.run_forever()
finally:
    loop.close()
协程技巧总结

一、运行协程的两种方法:
1. asyncio.wait( )

loop.run_until_complete(asyncio.wait(tasks))

2. asyncio.gather( )

loop.run_until_complete(asyncio.gather(*tasks))

二、创建 task 的两种方法:
1.需要提前声明 loop

# 用 get_event_loop 方法创建事件循环 loop
loop = asyncio.get_event_loop()
# 调用 loop 对象的 create_task 方法
task = loop.create_task(coroutine)

2.不需要提前声明 loop

# 调用 asyncio 的 ensure_future 方法
task = asyncio.ensure_future(coroutine)

三、获取结果的两种方法:
1. 绑定回调函数

# 创建一个任务协程
task = asyncio.ensure_future(coroutine)
# 绑定回调函数,callback 是一个普通函数
task.add_done_callback(callback)

2. 在 task 运行完后调用 result 方法

for task in tasks:
        print("Task ret:",task.result())
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容