切換
舊版
前往
大廳
主題

Python asyncio簡單整理

PoiPoi | 2020-08-08 20:22:45 | 巴幣 4 | 人氣 408

前言

Python為了避免產生blocking問題,替耗時的IO、計算或網路相關操作提供了asyncio,可以用並發的方式完成工作,同時最大限度地提高作業效率。(並發和並行的比較)

正文

協程和任務(Coroutines and Tasks)


協程指的是有宣告為async的函式

import asyncio

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

此時main()就是協程,無法直接被執行


協程可以被裝成任務,接續上面的程式碼

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上常常用到。

結語

其實這篇是整理幾個重點給我自己看的,文中只有簡單帶過常用的東西,如果需要更深層的知識需要自己去搜尋。

有任何錯誤請通知我。


創作回應

石頭吐司
推推
2020-08-08 21:27:00
PoiPoi
[e6]
2020-08-08 21:55:31
舒潔艾拉
不是 您也太猛
2020-08-14 00:18:41
PoiPoi
我爛 上面的石頭大老很電都不說話
2020-08-14 00:31:57

更多創作