協(xié)程與任務(wù)?

本節(jié)將簡述用于協(xié)程與任務(wù)的高層級(jí) API。

協(xié)程?

協(xié)程通過 async/await 語法進(jìn)行聲明,是編寫異步應(yīng)用的推薦方式。例如,以下代碼段 (需要 Python 3.7+) 打印 "hello",等待 1 秒,然后打印 "world":

>>> import asyncio

>>> async def main():
...     print('hello')
...     await asyncio.sleep(1)
...     print('world')

>>> asyncio.run(main())
hello
world

注意:簡單地調(diào)用一個(gè)協(xié)程并不會(huì)將其加入執(zhí)行日程:

>>> main()
<coroutine object main at 0x1053bb7c8>

要真正運(yùn)行一個(gè)協(xié)程,asyncio 提供了三種主要機(jī)制:

  • asyncio.run() 函數(shù)用來運(yùn)行最高層級(jí)的入口點(diǎn) "main()" 函數(shù) (參見上面的示例。)

  • 等待一個(gè)協(xié)程。以下代碼段會(huì)在等待 1 秒后打印 "hello",然后 再次 等待 2 秒后打印 "world":

    import asyncio
    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())
    

    預(yù)期的輸出:

    started at 17:13:52
    hello
    world
    finished at 17:13:55
    
  • asyncio.create_task() 函數(shù)用來并發(fā)運(yùn)行作為 asyncio 任務(wù) 的多個(gè)協(xié)程。

    讓我們修改以上示例,并發(fā) 運(yùn)行兩個(gè) say_after 協(xié)程:

    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')}")
    
        # Wait until both tasks are completed (should take
        # around 2 seconds.)
        await task1
        await task2
    
        print(f"finished at {time.strftime('%X')}")
    

    注意,預(yù)期的輸出顯示代碼段的運(yùn)行時(shí)間比之前快了 1 秒:

    started at 17:14:32
    hello
    world
    finished at 17:14:34
    

可等待對象?

如果一個(gè)對象可以在 await 語句中使用,那么它就是 可等待 對象。許多 asyncio API 都被設(shè)計(jì)為接受可等待對象。

可等待 對象有三種主要類型: 協(xié)程, 任務(wù)Future.

協(xié)程

Python 協(xié)程屬于 可等待 對象,因此可以在其他協(xié)程中被等待:

import asyncio

async def nested():
    return 42

async def main():
    # Nothing happens if we just call "nested()".
    # A coroutine object is created but not awaited,
    # so it *won't run at all*.
    nested()

    # Let's do it differently now and await it:
    print(await nested())  # will print "42".

asyncio.run(main())

重要

在本文檔中 "協(xié)程" 可用來表示兩個(gè)緊密關(guān)聯(lián)的概念:

  • 協(xié)程函數(shù): 定義形式為 async def 的函數(shù);

  • 協(xié)程對象: 調(diào)用 協(xié)程函數(shù) 所返回的對象。

asyncio 也支持舊式的 基于生成器的 協(xié)程。

任務(wù)

任務(wù) 被用來設(shè)置日程以便 并發(fā) 執(zhí)行協(xié)程。

當(dāng)一個(gè)協(xié)程通過 asyncio.create_task() 等函數(shù)被打包為一個(gè) 任務(wù),該協(xié)程將自動(dòng)排入日程準(zhǔn)備立即運(yùn)行:

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())

Futures

Future 是一種特殊的 低層級(jí) 可等待對象,表示一個(gè)異步操作的 最終結(jié)果。

當(dāng)一個(gè) Future 對象 被等待,這意味著協(xié)程將保持等待直到該 Future 對象在其他地方操作完畢。

在 asyncio 中需要 Future 對象以便允許通過 async/await 使用基于回調(diào)的代碼。

通常情況下 沒有必要 在應(yīng)用層級(jí)的代碼中創(chuàng)建 Future 對象。

Future 對象有時(shí)會(huì)由庫和某些 asyncio API 暴露給用戶,用作可等待對象:

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()
    )

一個(gè)很好的返回對象的低層級(jí)函數(shù)的示例是 loop.run_in_executor()

運(yùn)行 asyncio 程序?

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

執(zhí)行 coroutine coro 并返回結(jié)果。

此函數(shù)運(yùn)行傳入的協(xié)程,負(fù)責(zé)管理 asyncio 事件循環(huán)并 完結(jié)異步生成器。

當(dāng)有其他 asyncio 事件循環(huán)在同一線程中運(yùn)行時(shí),此函數(shù)不能被調(diào)用。

如果 debugTrue,事件循環(huán)將以調(diào)試模式運(yùn)行。

此函數(shù)總是會(huì)創(chuàng)建一個(gè)新的事件循環(huán)并在結(jié)束時(shí)關(guān)閉之。它應(yīng)當(dāng)被用作 asyncio 程序的主入口點(diǎn),理想情況下應(yīng)當(dāng)只被調(diào)用一次。

示例:

async def main():
    await asyncio.sleep(1)
    print('hello')

asyncio.run(main())

3.7 新版功能: 重要: 此函數(shù)是在 Python 3.7 中加入 asyncio 模塊,處于 暫定基準(zhǔn)狀態(tài)。

創(chuàng)建任務(wù)?

asyncio.create_task(coro)?

coro 協(xié)程 打包為一個(gè) Task 排入日程準(zhǔn)備執(zhí)行。返回 Task 對象。

該任務(wù)會(huì)在 get_running_loop() 返回的循環(huán)中執(zhí)行,如果當(dāng)前線程沒有在運(yùn)行的循環(huán)則會(huì)引發(fā) RuntimeError

此函數(shù) 在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用低層級(jí)的 asyncio.ensure_future() 函數(shù)。

async def coro():
    ...

# In Python 3.7+
task = asyncio.create_task(coro())
...

# This works in all Python versions but is less readable
task = asyncio.ensure_future(coro())
...

3.7 新版功能.

休眠?

coroutine asyncio.sleep(delay, result=None, *, loop=None)?

阻塞 delay 指定的秒數(shù)。

如果指定了 result,則當(dāng)協(xié)程完成時(shí)將其返回給調(diào)用者。

sleep() 總是會(huì)掛起當(dāng)前任務(wù),以允許其他任務(wù)運(yùn)行。

loop 參數(shù)已棄用,計(jì)劃在 Python 3.10 中移除。

以下協(xié)程示例運(yùn)行 5 秒,每秒顯示一次當(dāng)前日期:

import asyncio
import datetime

async def display_date():
    loop = asyncio.get_running_loop()
    end_time = loop.time() + 5.0
    while True:
        print(datetime.datetime.now())
        if (loop.time() + 1.0) >= end_time:
            break
        await asyncio.sleep(1)

asyncio.run(display_date())

并發(fā)運(yùn)行任務(wù)?

awaitable asyncio.gather(*aws, loop=None, return_exceptions=False)?

并發(fā) 運(yùn)行 aws 序列中的 可等待對象。

如果 aws 中的某個(gè)可等待對象為協(xié)程,它將自動(dòng)作為一個(gè)任務(wù)加入日程。

如果所有可等待對象都成功完成,結(jié)果將是一個(gè)由所有返回值聚合而成的列表。結(jié)果值的順序與 aws 中可等待對象的順序一致。

如果 return_exceptionsFalse (默認(rèn)),所引發(fā)的首個(gè)異常會(huì)立即傳播給等待 gather() 的任務(wù)。aws 序列中的其他可等待對象 不會(huì)被取消 并將繼續(xù)運(yùn)行。

如果 return_exceptionsTrue,異常會(huì)和成功的結(jié)果一樣處理,并聚合至結(jié)果列表。

如果 gather() 被取消,所有被提交 (尚未完成) 的可等待對象也會(huì) 被取消。

如果 aws 序列中的任一 Task 或 Future 對象 被取消,它將被當(dāng)作引發(fā)了 CancelledError 一樣處理 -- 在此情況下 gather() 調(diào)用 不會(huì) 被取消。這是為了防止一個(gè)已提交的 Task/Future 被取消導(dǎo)致其他 Tasks/Future 也被取消。

示例:

import asyncio

async def factorial(name, number):
    f = 1
    for i in range(2, number + 1):
        print(f"Task {name}: Compute factorial({i})...")
        await asyncio.sleep(1)
        f *= i
    print(f"Task {name}: factorial({number}) = {f}")

async def main():
    # Schedule three calls *concurrently*:
    await asyncio.gather(
        factorial("A", 2),
        factorial("B", 3),
        factorial("C", 4),
    )

asyncio.run(main())

# Expected output:
#
#     Task A: Compute factorial(2)...
#     Task B: Compute factorial(2)...
#     Task C: Compute factorial(2)...
#     Task A: factorial(2) = 2
#     Task B: Compute factorial(3)...
#     Task C: Compute factorial(3)...
#     Task B: factorial(3) = 6
#     Task C: Compute factorial(4)...
#     Task C: factorial(4) = 24

在 3.7 版更改: 如果 gather 本身被取消,則無論 return_exceptions 取值為何,消息都會(huì)被傳播。

屏蔽取消操作?

awaitable asyncio.shield(aw, *, loop=None)?

保護(hù)一個(gè) 可等待對象 防止其被 取消

如果 aw 是一個(gè)協(xié)程,它將自動(dòng)作為任務(wù)加入日程。

以下語句:

res = await shield(something())

相當(dāng)于:

res = await something()

不同之處 在于如果包含它的協(xié)程被取消,在 something() 中運(yùn)行的任務(wù)不會(huì)被取消。從 something() 的角度看來,取消操作并沒有發(fā)生。然而其調(diào)用者已被取消,因此 "await" 表達(dá)式仍然會(huì)引發(fā) CancelledError。

如果通過其他方式取消 something() (例如在其內(nèi)部操作) 則 shield() 也會(huì)取消。

如果希望完全忽略取消操作 (不推薦) 則 shield() 函數(shù)需要配合一個(gè) try/except 代碼段,如下所示:

try:
    res = await shield(something())
except CancelledError:
    res = None

超時(shí)?

coroutine asyncio.wait_for(aw, timeout, *, loop=None)?

等待 aw 可等待對象 完成,指定 timeout 秒數(shù)后超時(shí)。

如果 aw 是一個(gè)協(xié)程,它將自動(dòng)作為任務(wù)加入日程。

timeout 可以為 None,也可以為 float 或 int 型數(shù)值表示的等待秒數(shù)。如果 timeoutNone,則等待直到完成。

如果發(fā)生超時(shí),任務(wù)將取消并引發(fā) asyncio.TimeoutError.

要避免任務(wù) 取消,可以加上 shield()。

函數(shù)將等待直到目標(biāo)對象確實(shí)被取消,所以總等待時(shí)間可能超過 timeout 指定的秒數(shù)。

如果等待被取消,則 aw 指定的對象也會(huì)被取消。

loop 參數(shù)已棄用,計(jì)劃在 Python 3.10 中移除。

示例:

async def eternity():
    # Sleep for one hour
    await asyncio.sleep(3600)
    print('yay!')

async def main():
    # Wait for at most 1 second
    try:
        await asyncio.wait_for(eternity(), timeout=1.0)
    except asyncio.TimeoutError:
        print('timeout!')

asyncio.run(main())

# Expected output:
#
#     timeout!

在 3.7 版更改: 當(dāng) aw 因超時(shí)被取消,wait_for 會(huì)等待 aw 被取消。之前版本則將立即引發(fā) asyncio.TimeoutError

簡單等待?

coroutine asyncio.wait(aws, *, loop=None, timeout=None, return_when=ALL_COMPLETED)?

并發(fā)運(yùn)行 aws 指定的 可等待對象 并阻塞線程直到滿足 return_when 指定的條件。

如果 aws 中的某個(gè)可等待對象為協(xié)程,它將自動(dòng)作為任務(wù)加入日程。直接向 wait() 傳入?yún)f(xié)程對象已棄用,因?yàn)檫@會(huì)導(dǎo)致 令人迷惑的行為。

返回兩個(gè) Task/Future 集合: (done, pending)

用法:

done, pending = await asyncio.wait(aws)

loop 參數(shù)已棄用,計(jì)劃在 Python 3.10 中移除。

如指定 timeout (float 或 int 類型) 則它將被用于控制返回之前等待的最長秒數(shù)。

請注意此函數(shù)不會(huì)引發(fā) asyncio.TimeoutError。當(dāng)超時(shí)發(fā)生時(shí),未完成的 Future 或 Task 將在指定秒數(shù)后被返回。

return_when 指定此函數(shù)應(yīng)在何時(shí)返回。它必須為以下常數(shù)之一:

常數(shù)

描述

FIRST_COMPLETED

函數(shù)將在任意可等待對象結(jié)束或取消時(shí)返回。

FIRST_EXCEPTION

函數(shù)將在任意可等待對象因引發(fā)異常而結(jié)束時(shí)返回。當(dāng)沒有引發(fā)任何異常時(shí)它就相當(dāng)于 ALL_COMPLETED。

ALL_COMPLETED

函數(shù)將在所有可等待對象結(jié)束或取消時(shí)返回。

wait_for() 不同,wait() 在超時(shí)發(fā)生時(shí)不會(huì)取消可等待對象。

注解

wait() 會(huì)自動(dòng)將協(xié)程作為任務(wù)加入日程,以后將以 (done, pending) 集合形式返回顯式創(chuàng)建的任務(wù)對象。因此以下代碼并不會(huì)有預(yù)期的行為:

async def foo():
    return 42

coro = foo()
done, pending = await asyncio.wait({coro})

if coro in done:
    # This branch will never be run!

以上代碼段的修正方法如下:

async def foo():
    return 42

task = asyncio.create_task(foo())
done, pending = await asyncio.wait({task})

if task in done:
    # Everything will work as expected now.

直接向 wait() 傳入?yún)f(xié)程對象的方式已棄用。

asyncio.as_completed(aws, *, loop=None, timeout=None)?

?并發(fā)地運(yùn)行 aws 集合中的 可等待對象。返回一個(gè) Future 對象的迭代器。返回的每個(gè) Future 對象代表來自剩余可等待對象集合的最早結(jié)果。

如果在所有 Future 對象完成前發(fā)生超時(shí)則將引發(fā) asyncio.TimeoutError。

示例:

for f in as_completed(aws):
    earliest_result = await f
    # ...

來自其他線程的日程安排?

asyncio.run_coroutine_threadsafe(coro, loop)?

向指定事件循環(huán)提交一個(gè)協(xié)程。線程安全。

返回一個(gè) concurrent.futures.Future 以等待來自其他 OS 線程的結(jié)果。

此函數(shù)應(yīng)該從另一個(gè) OS 線程中調(diào)用,而非事件循環(huán)運(yùn)行所在線程。示例:

# Create a coroutine
coro = asyncio.sleep(1, result=3)

# Submit the coroutine to a given loop
future = asyncio.run_coroutine_threadsafe(coro, loop)

# Wait for the result with an optional timeout argument
assert future.result(timeout) == 3

如果在協(xié)程內(nèi)產(chǎn)生了異常,將會(huì)通知返回的 Future 對象。它也可被用來取消事件循環(huán)中的任務(wù):

try:
    result = future.result(timeout)
except asyncio.TimeoutError:
    print('The coroutine took too long, cancelling the task...')
    future.cancel()
except Exception as exc:
    print(f'The coroutine raised an exception: {exc!r}')
else:
    print(f'The coroutine returned: {result!r}')

參見 concurrency and multithreading 部分的文檔。

不同與其他 asyncio 函數(shù),此函數(shù)要求顯式地傳入 loop 參數(shù)。

3.5.1 新版功能.

內(nèi)省?

asyncio.current_task(loop=None)?

返回當(dāng)前運(yùn)行的 Task 實(shí)例,如果沒有正在運(yùn)行的任務(wù)則返回 None。

如果 loopNone 則會(huì)使用 get_running_loop() 獲取當(dāng)前事件循環(huán)。

3.7 新版功能.

asyncio.all_tasks(loop=None)?

返回事件循環(huán)所運(yùn)行的未完成的 Task 對象的集合。

如果 loopNone,則會(huì)使用 get_running_loop() 獲取當(dāng)前事件循環(huán)。

3.7 新版功能.

Task 對象?

class asyncio.Task(coro, *, loop=None)?

一個(gè)與 Future 類似 的對象,可運(yùn)行 Python 協(xié)程。非線程安全。

Task 對象被用來在事件循環(huán)中運(yùn)行協(xié)程。如果一個(gè)協(xié)程在等待一個(gè) Future 對象,Task 對象會(huì)掛起該協(xié)程的執(zhí)行并等待該 Future 對象完成。當(dāng)該 Future 對象 完成,被打包的協(xié)程將恢復(fù)執(zhí)行。

事件循環(huán)使用協(xié)同日程調(diào)度: 一個(gè)事件循環(huán)每次運(yùn)行一個(gè) Task 對象。而一個(gè) Task 對象會(huì)等待一個(gè) Future 對象完成,該事件循環(huán)會(huì)運(yùn)行其他 Task、回調(diào)或執(zhí)行 IO 操作。

使用高層級(jí)的 asyncio.create_task() 函數(shù)來創(chuàng)建 Task 對象,也可用低層級(jí)的 loop.create_task()ensure_future() 函數(shù)。不建議手動(dòng)實(shí)例化 Task 對象。

要取消一個(gè)正在運(yùn)行的 Task 對象可使用 cancel() 方法。調(diào)用此方法將使該 Task 對象拋出一個(gè) CancelledError 異常給打包的協(xié)程。如果取消期間一個(gè)協(xié)程正在等待一個(gè) Future 對象,該 Future 對象也將被取消。

cancelled() 可被用來檢測 Task 對象是否被取消。如果打包的協(xié)程沒有抑制 CancelledError 異常并且確實(shí)被取消,該方法將返回 True。

asyncio.TaskFuture 繼承了其除 Future.set_result()Future.set_exception() 以外的所有 API。

Task 對象支持 contextvars 模塊。當(dāng)一個(gè) Task 對象被創(chuàng)建,它將復(fù)制當(dāng)前上下文,然后在復(fù)制的上下文中運(yùn)行其協(xié)程。

在 3.7 版更改: 加入對 contextvars 模塊的支持。

cancel()?

請求取消 Task 對象。

這將安排在下一輪事件循環(huán)中拋出一個(gè) CancelledError 異常給被封包的協(xié)程。

協(xié)程在之后有機(jī)會(huì)進(jìn)行清理甚至使用 try ... ... except CancelledError ... finally 代碼塊抑制異常來拒絕請求。不同于 Future.cancel(),Task.cancel() 不保證 Task 會(huì)被取消,雖然抑制完全取消并不常見,也很不鼓勵(lì)這樣做。

以下示例演示了協(xié)程是如何偵聽取消請求的:

async def cancel_me():
    print('cancel_me(): before sleep')

    try:
        # Wait for 1 hour
        await asyncio.sleep(3600)
    except asyncio.CancelledError:
        print('cancel_me(): cancel sleep')
        raise
    finally:
        print('cancel_me(): after sleep')

async def main():
    # Create a "cancel_me" Task
    task = asyncio.create_task(cancel_me())

    # Wait for 1 second
    await asyncio.sleep(1)

    task.cancel()
    try:
        await task
    except asyncio.CancelledError:
        print("main(): cancel_me is cancelled now")

asyncio.run(main())

# Expected output:
#
#     cancel_me(): before sleep
#     cancel_me(): cancel sleep
#     cancel_me(): after sleep
#     main(): cancel_me is cancelled now
cancelled()?

如果 Task 對象 被取消 則返回 True。

當(dāng)使用 cancel() 發(fā)出取消請求時(shí) Task 會(huì)被 取消,其封包的協(xié)程將傳播被拋入的 CancelledError 異常。

done()?

如果 Task 對象 已完成 則返回 True

當(dāng) Task 所封包的協(xié)程返回一個(gè)值、引發(fā)一個(gè)異?;?Task 本身被取消時(shí),則會(huì)被認(rèn)為 已完成。

result()?

返回 Task 的結(jié)果。

如果 Task 對象 已完成,其封包的協(xié)程的結(jié)果會(huì)被返回 (或者當(dāng)協(xié)程引發(fā)異常時(shí),該異常會(huì)被重新引發(fā)。)

如果 Task 對象 被取消,此方法會(huì)引發(fā)一個(gè) CancelledError 異常。

如果 Task 對象的結(jié)果還不可用,此方法會(huì)引發(fā)一個(gè) InvalidStateError 異常。

exception()?

返回 Task 對象的異常。

如果所封包的協(xié)程引發(fā)了一個(gè)異常,該異常將被返回。如果所封包的協(xié)程正常返回則該方法將返回 None。

如果 Task 對象 被取消,此方法會(huì)引發(fā)一個(gè) CancelledError 異常。

如果 Task 對象尚未 完成,此方法將引發(fā)一個(gè) InvalidStateError 異常。

add_done_callback(callback, *, context=None)?

添加一個(gè)回調(diào),將在 Task 對象 完成 時(shí)被運(yùn)行。

此方法應(yīng)該僅在低層級(jí)的基于回調(diào)的代碼中使用。

要了解更多細(xì)節(jié)請查看 Future.add_done_callback() 的文檔。

remove_done_callback(callback)?

從回調(diào)列表中移除 callback 。

此方法應(yīng)該僅在低層級(jí)的基于回調(diào)的代碼中使用。

要了解更多細(xì)節(jié)請查看 Future.remove_done_callback() 的文檔。

get_stack(*, limit=None)?

返回此 Task 對象的??蚣芰斜怼?/p>

如果所封包的協(xié)程未完成,這將返回其掛起所在的棧。如果協(xié)程已成功完成或被取消,這將返回一個(gè)空列表。如果協(xié)程被一個(gè)異常終止,這將返回回溯框架列表。

框架總是從按從舊到新排序。

每個(gè)被掛起的協(xié)程只返回一個(gè)??蚣?。

可選的 limit 參數(shù)指定返回框架的數(shù)量上限;默認(rèn)返回所有框架。返回列表的順序要看是返回一個(gè)棧還是一個(gè)回溯:棧返回最新的框架,回溯返回最舊的框架。(這與 traceback 模塊的行為保持一致。)

print_stack(*, limit=None, file=None)?

打印此 Task 對象的棧或回溯。

此方法產(chǎn)生的輸出類似于 traceback 模塊通過 get_stack() 所獲取的框架。

limit 參數(shù)會(huì)直接傳遞給 get_stack()

file 參數(shù)是輸出所寫入的 I/O 流;默認(rèn)情況下輸出會(huì)寫入 sys.stderr。

classmethod all_tasks(loop=None)?

返回一個(gè)事件循環(huán)中所有任務(wù)的集合。

默認(rèn)情況下將返回當(dāng)前事件循環(huán)中所有任務(wù)。如果 loopNone,則會(huì)使用 get_event_loop() 函數(shù)來獲取當(dāng)前事件循環(huán)。

此方法 已棄用 并將在 Python 3.9 中移除。請改用 asyncio.all_tasks() 函數(shù)。

classmethod current_task(loop=None)?

返回當(dāng)前運(yùn)行任務(wù)或 None。

如果 loopNone,則會(huì)使用 get_event_loop() 函數(shù)來獲取當(dāng)前事件循環(huán)。

此方法 已棄用 并將在 Python 3.9 中移除。請改用 asyncio.current_task() 函數(shù)。

基于生成器的協(xié)程?

注解

對基于生成器的協(xié)程的支持 已棄用 并計(jì)劃在 Python 3.10 中移除。

基于生成器的協(xié)程是 async/await 語法的前身。它們是使用 yield from 語句創(chuàng)建的 Python 生成器,可以等待 Future 和其他協(xié)程。

基于生成器的協(xié)程應(yīng)該使用 @asyncio.coroutine 裝飾,雖然這并非強(qiáng)制。

@asyncio.coroutine?

用來標(biāo)記基于生成器的協(xié)程的裝飾器。

此裝飾器使得舊式的基于生成器的協(xié)程能與 async/await 代碼相兼容:

@asyncio.coroutine
def old_style_coroutine():
    yield from asyncio.sleep(1)

async def main():
    await old_style_coroutine()

此裝飾器 已棄用 并計(jì)劃在 Python 3.10 中移除。

此裝飾器不應(yīng)該被用于 async def 協(xié)程。

asyncio.iscoroutine(obj)?

如果 obj 是一個(gè) 協(xié)程對象 則返回 True。

此方法不同于 inspect.iscoroutine() 因?yàn)樗鼘谏善鞯膮f(xié)程返回 True。

asyncio.iscoroutinefunction(func)?

如果 func 是一個(gè) 協(xié)程函數(shù) 則返回 True。

此方法不同于 inspect.iscoroutinefunction() 因?yàn)樗鼘σ?@coroutine 裝飾的基于生成器的協(xié)程函數(shù)返回 True。