asyncio简明教程

1. 前言

asyncio 是用来编写并发代码的库,使用 async/await 语法。

asyncio 被用作多个提供高性能 Python 异步框架的基础,包括网络和网站服务,数据库连接库,分布式任务队列等等。asyncio 往往是构建 IO 密集型的最佳选择。

asyncio 是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。如果你在 Python 早期版本中,想使用类似的功能,可以了解一下 gevent 库和 twisted 库。

2. asyncio定义

asyncio 模块提供了一个围绕事件循环的框架。事件循环就是等待事件发生,然后对事件进行操作,依赖这种方式实现异步IO。

  • event_loop:时间循环,开启之后,可以将协程注册进来。
  • task:一个协程对象就是一个可以挂起的函数,任务是对协程的进一步封装,其中包含了任务的各种状
  • future:代表将来执行或没有执行的任务的结果。task可以说是future的子类。

下面以一段代码为例子

import asyncio

@asyncio.coroutine
def hello1():
    print("request https://www.xtuz.net 1")
    # 异步调用asyncio.sleep(1):
    yield from asyncio.sleep(3)
    print("response https://www.xtuz.net 1")

@asyncio.coroutine
def hello2():
    print("request https://www.xtuz.net 2")
    # 异步调用asyncio.sleep(1):
    yield from asyncio.sleep(2)
    print("response https://www.xtuz.net 2")



# 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
tasks = [hello1(), hello2()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

在asyncio库中,协程使用 @asyncio.coroutine 装饰来定义一个Task,并将放入到 event_loop 的循环中,使用 yield from 来驱动。

上述代码输出如下:

request https://www.xtuz.net 1
request https://www.xtuz.net 2
response https://www.xtuz.net 2
response https://www.xtuz.net 1

在python3.5中作了如下更改

@asyncio.coroutine => async

yield from => await

基于此,我们可以将上述代码进行改写,代码看起来要逻辑清晰很多。

import asyncio

async def hello1():
    print("request https://www.xtuz.net 1")
    # 异步调用asyncio.sleep(1):
    await asyncio.sleep(3)
    print("response https://www.xtuz.net 1")

async def hello2():
    print("request https://www.xtuz.net 2")
    # 异步调用asyncio.sleep(1):
    await asyncio.sleep(2)
    print("response https://www.xtuz.net 2")

# 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
tasks = [hello1(), hello2()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

2.1 创建Task

loop.create_task()

接收一个协程,返回一个 asyncio.Task 的实例,也是 asyncio.Future 的实例。

返回值可直接传入 run_until_complete()

2.2 获取Task返回值

task.result()

可通过调用 task.result() 方法来获取协程的返回值,但是只有运行完毕后才能获取,若没有运行完毕,result()方法不会阻塞去等待结果,而是抛出 asyncio.InvalidStateError 错误。

2.3 控制Task

asyncio.wait()

asyncio.wait() 是一个协程,不会阻塞,立即返回,返回的是协程对象。传入的参数是future或协程构成的可迭代对象。最后将返回值传给run_until_complete()加入事件循环。

2.4 动态添加Task

  • *loop.call_soon_threadsafe() * 等待此函数返回后马上调用回调函数,返回值是一个 asyncio.Handle 对象,此对象内只有一个方法为 cancel()方法,用来取消回调函数。
  • *loop.call_soon() * 与call_soon_threadsafe()类似,call_soon_threadsafe() 是线程安全
  • loop.call_later() 延迟多少秒后执行回调函数
  • loop.call_at() 在指定时间执行回调函数,这里的时间统一使用 loop.time() 来替代 time.sleep()
  • asyncio.run_coroutine_threadsafe() 动态的加入协程,参数为一个回调函数和一个loop对象,返回值为future对象,通过future.result()获取回调函数返回值

3. asyncio启动一个协程

asyncio事件循环可以通过多种不同的方法启动一个协程。一般对于入口函数,最简答的方法就是使用run_until_complete(),并将协程直接传入这个方法。

import asyncio

async def foo():
    print("https://www.xtuz.net")

loop = asyncio.get_event_loop()
loop.run_until_complete(foo())
loop.close()

4. asyncio协程获取返回值

run_until_complete 可以获取协程的返回值,如果没有给定返回值,则像函数一样,默认返回None

import asyncio

async def foo():
    print("https://www.xtuz.net")
    return 'foo'

loop = asyncio.get_event_loop()
ret = loop.run_until_complete(foo())
print(ret)
loop.close()

5. asyncio中协程相互调用

一个协程可以启动另一个协程,从而可以任务根据工作内容,封装到不同的协程中。我们可以在协程中使用await关键字,链式的调度协程,来形成一个协程任务流。

import asyncio

async def foo2(url):
    print(url)
    return 'foo2'

async def foo():
    print("https://www.xtuz.net")
    ret = await foo2('https://www.cmypsc.com')
    return ret

loop = asyncio.get_event_loop()
ret = loop.run_until_complete(foo())
print(ret)
loop.close()

6. 小结

asyncio提供了完善的异步IO支持;

异步操作需要在coroutine中通过await完成;

多个coroutine可以封装成一组Task然后并发执行。

参考阅读


相关主题:
相关推荐
  1. 华东师范大学第二附属中学(紫竹校区)
  2. 北京七色光艺术幼儿园 - 北京幼儿园黄页
  3. Python Selenium find_element_by_css_selector 如何处理多个class
  4. 别忽略了身边的小事
  5. 老熊和大鼻狗
  6. 西安市未央区金贝贝幼儿园 - 西安幼儿园黄页
  7. 新乐市马头铺中学
  8. 上海市嘉定区新怡幼儿园 - 上海幼儿园黄页
  9. 鑫龙幼儿园 - 苏州幼儿园黄页
  10. 武汉推出越王勾践剑交通卡
  11. 苍蝇和学生
  12. 央媒聚焦!国庆假期173.78万人次打卡大美黄陂
  13. 上海飞翔日本人补习中心
  14. 薛谭学歌
  15. 上海市徐汇区培蕾幼稚园(梅陇三村总园) - 上海幼儿园黄页
  16. 易中天给英雄武汉的一首诗 - 武汉新鲜事
  17. 株洲市第十九中学
  18. 广州增城区红苗幼儿园 - 广州幼儿园黄页
  19. 鞍山市海城市西柳市场幼儿园 - 鞍山幼儿园黄页
  20. 月季和玫瑰
  21. 济南市匡山小学
  22. 广州增城区新塘镇沙埔小学
  23. 鸟尽弓藏
  24. python3.5升级python3.6后出现 No module named apt_pkg 异常
  25. 咸阳市彬县车家庄中心幼儿园 - 咸阳市幼儿园黄页
  26. 佳佳迟到了
  27. 小啄木鸟长大了
  28. 湖北将发放消费券 - 武汉新鲜事
  29. 武汉一女子七天被骗220万
  30. 西交利物浦大学附属学校
  31. 奥迪客户不满加价,被武汉4S店销售群殴
  32. 电池技术 - 电动汽车的核心
  33. 武汉动物园火烈鸟孔雀排队打疫苗
  34. 天津市静海县杨成庄乡梅厂明德小学
  35. SNMP监控详解
  36. 佛冈县城东中学
  37. 青岛市市北区北仲路第二小学(北仲路二小)
  38. 公主和大蟒
  39. Python的起源 - 二十年前的故事
  40. Python源码剖析 - 对象初探
  41. 深圳市盐田区乐群小学
  42. 长春市第五十六中学
  43. 郑州市第一零一中学(原铁路一中)
  44. 华东师范大学附属杨行中学
  45. 长沙市浏阳市沙市镇东门完全小学
  46. iconv - Mac OS 文本格式转换工具
  47. 百名网媒总编辑登上知音号欣赏武汉夜色
  48. 南昌铁路局鹰潭铁路职工第三子弟小学
  49. ubuntu环境安装opencv与python-opencv
  50. 哈尔滨市万宝镇万有小学校
  51. 吉林市船营区晓飞双语幼儿园 - 吉林市幼儿园黄页
  52. 中山市南朗石门小学
  53. 什么是TOGAF - TOGAF系列教程(1)
  54. 一根羽毛
  55. Python公开课 - 正则表达式
  56. 武汉00后大二学妹拍视频月入七十万
  57. 上海市浦东新区花木中心小学
  58. 上海市浦东新区东沟幼儿园(新行部) - 上海幼儿园黄页
  59. 上海市松江六中
  60. 脱单!武汉的相亲角在哪你知道吗?