使用Python的asyncio時,可以把一個同步的函數放到線程池中執行從而避免這個函數阻塞asyncio自身的事件循環。比如可以把requests庫的請求放進去
async def to_thread_do_request(url):return await asyncio.to_thread(requests.get, url)
這個to_thread_do_request
方法就不會造成asyncio的阻塞,反而下面這樣直接調用一個下面這樣把requests.get簡單包在一個async函數里則會造成的協程的阻塞
async def do_request(url):return requests.get(url)
不過在使用asyncio.to_thread
函數時,我們需要注意一點,即asyncio的上下文,也就是通過contextvars來保存的內容通過asyncio.to_thread
來執行時與調用者否是一致的?
這個可以大致看一下asyncio.to_thread
的實現,我們會發現,對于context來說,這個to_thread
會先調用contextvars.copy_context
方法把當前的context整體復制到ctx
變量中,然后再通過ctx.run
來執行其實際任務。這樣通過asyncio.to_thread
來執行的函數,與調用方的context是一致的,可以放心的把一些需要獲取contextvars的工作放在里面跑。