前言
Python為了避免產生blocking問題,替耗時的IO、計算或網路相關操作提供了asyncio,可以用並發的方式完成工作,同時最大限度地提高作業效率。(並發和並行的比較)
正文
協程和任務(Coroutines and Tasks)
1.何謂協程?
協程指的是有宣告為async的函式
import asyncio async def main(): print('hello') await asyncio.sleep(1) print('world') |
此時main()就是協程,無法直接被執行
2.何謂任務?
協程可以被裝成任務,接續上面的程式碼
task = asyncio.create_task(main()) |
此時task會是一個任務,任務比起一般協程能做出更多流程控制。
協程和任務的使用
若要使用協程和任務,需要使用await
await task await main() |
在這邊要注意,await task和await main()都會回傳main的執行結果,但是task是在create_task()沒多久後就執行了(會被丟進事件迴圈等待執行),後者則是執行await main()時才會被執行。
補充:關於task的那些事(必看)
Queue Lock與Event
可以用來控制執行情況
Queue 佇列 先進先出
可以塞入需要處理的物件,在音樂機器人等需要有佇列時很有用
queue = asyncio.Queue() await queue.put(Obj) something = await queue.get() |
能調控IO資源的取得,上鎖以後不能被使用,直到鎖被釋放為止,通常搭配async with使用
lock = asyncio.Lock() #程式會等到鎖被釋放才進入該區塊 async with lock: #access shared state |
能調控程式是否要繼續向下執行(wait()),常用於callback函數中。
內部有個參數預設是false,可透過函數控制。當執行wait()時,若參數是true就會立刻繼續執行,否則會持續等待。
async def waiter(event): print('waiting for it ...') await event.wait() print('... got it!') async def main(): # Create an Event object. event = asyncio.Event() # Spawn a Task to wait until 'event' is set. waiter_task = asyncio.create_task(waiter(event)) # Sleep for 1 second and set the event. await asyncio.sleep(1) event.set() # Wait until the waiter task is finished. await waiter_task asyncio.run(main()) |
對抗耗時的IO操作
面對耗時的IO操作,可以使用比較低層的操作方法
import asyncio async def blocking_io(): #do something asyncio.sleep(10) return 'Fuck My Life' async def main(): loop = asyncio.get_running_loop() result = await loop.run_in_executor(None, blocking_io) print(result) asyncio.run(main()) |
用這種方法處理,主線程就不會卡住,在Discord Bot上常常用到。
結語
其實這篇是整理幾個重點給我自己看的,文中只有簡單帶過常用的東西,如果需要更深層的知識需要自己去搜尋。
有任何錯誤請通知我。