Python 簡易手冊
單元 53 - 協程
協程 (coroutine) 是指暫停目前執行的程式 (program) ,等待另一個程式執行完畢,然後才重啟原本暫停的程式繼續執行,這需要用到標準程式庫 (standard library) 中的 asyncio ,然後用關鍵字 (keyword) async 定義協程函數 (function) ,等待要先執行的工作則是放在 await 陳述 (statement) ,簡單舉例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 從標準程式庫引入 asyncio import asyncio # 定義協程函數 async def delay_print(): # 暫停 10 秒 await asyncio.sleep(10) # 印出訊息 print("Something happened...") # 執行協程函數 asyncio.run(delay_print()) # 檔名: async_demo.py # 說明: 《Python簡易手冊》的範例 # 網址: http://kaiching.org # 作者: Kaiching Chang # 時間: 2024 年 3 月 |
單元 44 - 函數與 return 陳述介紹如何定義函數。
第 2 行先引入標準程式庫中的 asyncio
1 2 | # 從標準程式庫引入 asyncio import asyncio |
第 5 行定義協程函數
4 5 6 7 8 9 | # 定義協程函數 async def delay_print(): # 暫停 10 秒 await asyncio.sleep(10) # 印出訊息 print("Something happened...") |
注意第 7 行是 await 陳述,關鍵字 await 之後可以放任何要先執行的程式碼,協程函數執行到這裡,會先暫停,然後執行 await 之後的程式碼,等到 await 之後的程式碼執行完畢,才會回到協程函數繼續執行下一行程式碼
6 7 | # 暫停 10 秒 await asyncio.sleep(10) |
上面 await 之後為 asyncio.sleep(10) ,就字面上意義是睡覺,在程式是指不做任何事情,引數 (argument) 10 是指 10 秒,所以這裡是單純等待 10 秒。
底下執行部分需要把協程函數 delay_print() 放在 asyncio.run() 中呼叫
11 12 | # 執行協程函數 asyncio.run(delay_print()) |
執行結果就是會先等待
> python async_demo.py |
10 秒後印出訊息
Something happened... |
> |
如果協程函數中用到關鍵字 yield ,這會是協程產生器 (async generator) ,要在另一個協程函數用 async for 依序取得協程產生器產生的值,舉例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 從標準程式庫引入 asyncio import asyncio # 定義協程產生器函數 async def do_something(): for i in range(10): if i % 2 != 0: yield i # 定義協程函數 async def main(): async for i in do_something(): await asyncio.sleep(1) print(i) # 執行協程函數 asyncio.run(main()) # 檔名: async_demo2.py # 說明: 《Python簡易手冊》的範例 # 網址: http://kaiching.org # 作者: Kaiching Chang # 時間: 2024 年 3 月 |
單元 50 - 產生器介紹如何定義產生器 (generator) 。
async for 在第 12 行,暫停一秒然後印出產生的數字
10 11 12 13 14 | # 定義協程函數 async def main(): async for i in do_something(): await asyncio.sleep(1) print(i) |
注意協程產生器不能用 next() 取值,完整執行結果如下
> python async_demo2.py |
1 3 5 7 9 |
> |
如果有多個協程任務,這時可以用 async with 來處理,舉例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # 從標準程式庫引入 asyncio import asyncio # 定義協程函數 async def print_after(delay, what): await asyncio.sleep(delay) print(what) # 定義執行多個協程任務的函數 async def main(): async with asyncio.TaskGroup() as tg: task1 = tg.create_task( print_after(2, '2 seconds...')) task2 = tg.create_task( print_after(5, '5 seconds...')) # 執行協程函數 asyncio.run(main()) # 檔名: async_demo3.py # 說明: 《Python簡易手冊》的範例 # 網址: http://kaiching.org # 作者: Kaiching Chang # 時間: 2024 年 3 月 |
單元 28 - with 陳述介紹如何關鍵字 with 的用法。
async with 在第 11 行,後面是接 asyncio.TaskGroup() ,這是做協程任務管理的物件,所以底下要用 create_task() 方法建立協程任務,這裡是執行後 2 秒印出第一次訊息, 5 秒印出第二次訊息,完整執行結果如下
> python async_demo3.py |
2 seconds... 5 seconds... |
> |
參考資料
- https://docs.python.org/3/reference/compound_stmts.html#coroutines
- https://docs.python.org/3/library/asyncio-task.html