python异步io协程读文件_asyncio异步IO--协程(Coroutine)与任务(Task)详解

说明:本文翻译自Coroutines and Tasks,主要介绍asyncio中用于处理协程和任务的方法和接口。在翻译过程中,译者在官方文档的基础上增加了部分样例代码和示意图表,以帮助读者对文档的理解。本文所述内容主要针对Python3.7,对3.7之前的版本有可能不适用,敬请注意。原创内容,转载请注明出处。

译者:马鸣谦

协程

协程(coroutines)是通过async/await定义函数或方法,是使用asyncio进行异步编程的首选途径。如下,是一个协程的例子:

import asyncio

async def main():

print("hello")

await asyncio.sleep(1)

print("world")

上例中的 main 方法就是我们定义的协程 。

我们在交互环境(Python3.7)下执行以上代码,看看效果:

>>> import asyncio

>>> async def main():

... print("hello")

... await asyncio.sleep(1)

... print("world")

>>> asyncio.run(main())

hello

world

需要注意的是:如果像执行普通代码一样直接调用main(),只会返回一个coroutine对象,main()方法内的代码不会执行:

>>> main() #直接执行`main()`返回的是一个`coroutine对象`。

实际上,asyncio提供了三种执行协程的机制:

使用asyncio.run()执行协程。一般用于执行最顶层的入口函数,如main()。

await一个协程。一般用于在一个协程中调用另一协程。 如下是一个示例:

>>> import time

>>> async def say_after(delay,what):

await asyncio.sleep(delay)

print(what)

>>> async def main():

print(f"started at {time.strftime('%X')}")

await say_after(1,"hello")

await say_after(2,"world")

print(f"finished at {time.strftime('%X')}")

>>> asyncio.run(main())

started at 16:47:10

hello

world

finished at 16:47:13

执行耗时 3秒

3. 用asyncio.create_task()方法将Coroutine(协程)封装为Task(任务)。一般用于实现异步并发操作。 需要注意的是,只有在当前线程存在事件循环的时候才能创建任务(Task)。

我们修改以上的例程,并发执行 两个say_after协程。

async def main():

task1 = asyncio.create_task(say_after(1,"hello"))

task2 = asyncio.create_task(say_after(2,"world"))

print(f"started at {time.strftime('%X')}")

await task1

await task2

print(f"finished at {time.strftime('%X')}")

执行asyncio.run(main()),结果如下:

started at 17:01:34

hello

world

finished at 17:01:36

耗时2秒

“可等待”对象(Awaitables)

如果一个对象能够被用在await表达式中,那么我们称这个对象是可等待对象(awaitable object)。很多asyncio API都被设计成了可等待的。

主要有三类可等待对象:

协程coroutine

任务Task

未来对象Future。

Coroutine(协程)

Python的协程是可等待的(awaitable),因此能够被其他协程用在await表达式中。

import asyncio

async def nested():

print("something")

async def main():

# 如果直接调用 "nested()",什么都不会发生.

# 直接调用的时候只是创建了一个 协程对象 ,但这个对象没有被 await,

# 所以它并不会执行.

nested()

# 那么我们 await 这个协程,看看会是什么结果:

await nested() # 将会打印 "something".

asyncio.run(main())

重要:在这篇文章中,术语coroutine或协程指代两个关系紧密的概念:

协程函数(coroutine function):由async def定义的函数;

协程对象(coroutine object):调用 协程函数返回的对象。

asyncio也支持传统的基于生成器的协程。

Task(任务)

Task用来 并发的 调度协程。

当一个协程通过类似 asyncio.create_task() 的函数被封装进一个 Task时,这个协程 会很快被自动调度执行:

import asyncio

async def nested():

return 42

async def main():

# Schedule nested() to run soon concurrently

# with "main()".

task = asyncio.create_task(nested())

# "task" can now be used to cancel "nested()", or

# can simply be awaited to wait until it is complete:

await task

asyncio.run(main())

Future(未来对象)

Future 是一种特殊的 底层 可等待对象,代表一个异步操作的最终结果。

当一个Future对象被await的时候,表示当前的协程会持续等待,直到 Future对象所指向的异步操作执行完毕。

在asyncio中,Future对象能使基于回调的代码被用于asyn/await表达式中。

一般情况下,在应用层编程中,没有必要 创建Future对象。

有时候,有些Future对象会被一些库和asyncio API暴露出来,我们可以await它们:

async def main():

await function_that_returns_a_future_object()

# this is also valid:

await asyncio.gather(

function_that_returns_a_future_object(),

some_python_coroutine()

)

底层函数返回Future对象的一个例子是:loop.run_in_executor

执行asyncio程序

asyncio.run(coro, * , debug=False)

这个函数运行coro参数指定的 协程,负责 管理asyncio事件循环 , 终止异步生成器。

在同一个线程中,当已经有asyncio事件循环在执行时,不能调用此函数。

如果debug=True,事件循环将运行在 调试模式。

此函数总是创建一个新的事件循环,并在最后关闭它。建议将它用作asyncio程序的主入口,并且只调用一次。

Python3.7新增

重要:这个函数是在Python3.7被临时添加到asyncio中的。

创建Task

asyncio.create_task(coro)

将coro参数指定的协程(coroutine)封装到一个Task中,并调度执行。返回值是一个Task对象。

任务在由get_running_loop()返回的事件循环(loop)中执行。如果当前线程中没有正在运行的事件循环,将会引发RuntimeError异常:

import asyncio

async def coro_1():

print("do somthing")

task = asyncio.create_task(coro_1())

因为当前线程中没有正运行的事件循环,所以引发异常:

Traceback (most recent call last):

File "C:\Program Files\Pyt

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值