[英]How to use run_in_executor right?
我嘗試使用run_in_executor
並提出一些問題。 這是代碼(基本上來自docs的copypast)
import asyncio
import concurrent.futures
def cpu_bound(val):
# CPU-bound operations will block the event loop:
# in general it is preferable to run them in a
# process pool.
print(f'Start task: {val}')
sum(i * i for i in range(10 ** 7))
print(f'End task: {val}')
async def async_task(val):
print(f'Start async task: {val}')
while True:
print(f'Tick: {val}')
await asyncio.sleep(1)
async def main():
loop = asyncio.get_running_loop()
## Options:
for i in range(5):
loop.create_task(async_task(i))
# 1. Run in the default loop's executor:
# for i in range(10):
# loop.run_in_executor(
# None, cpu_bound, i)
# print('default thread pool')
# 2. Run in a custom thread pool:
# with concurrent.futures.ThreadPoolExecutor(max_workers=10) as pool:
# for i in range(10):
# loop.run_in_executor(
# pool, cpu_bound, i)
# print('custom thread pool')
# 3. Run in a custom process pool:
with concurrent.futures.ProcessPoolExecutor(max_workers = 10) as pool:
for i in range(10):
loop.run_in_executor(
pool, cpu_bound, i)
print('custom process pool')
while True:
await asyncio.sleep(1)
asyncio.run(main())
情況1: run_in_executor
其中executor
是None
: async_task
的執行與cpu_bound
的執行同時執行。
在其他情況下, async_task
將在cpu_bound
完成后執行。 我ProcessPoolExecutor
我們使用ProcessPoolExecutor
任務不應該阻塞循環。 我哪里錯了?
在其他情況下,
async_task
將在cpu_bound
完成后執行。 我ProcessPoolExecutor
我們使用ProcessPoolExecutor
任務不應該阻塞循環。 我哪里錯了?
問題是with XXXPoolExecutor()
在with
塊的末尾關閉池。 池關閉等待掛起的任務完成,這會阻止事件循環並與asyncio不兼容。 由於您的第一個變體不涉及with
語句,因此它沒有此問題。
解決方案只是刪除with
語句並創建一次池(例如在頂層或在main()
),並在函數中使用它。 如果您願意,可以在asyncio.run()
完成后通過調用pool.shutdown()
顯式關閉池。
另請注意,您永遠不會等待 loop.run_in_executor
返回的期貨。 這是一個錯誤,asyncio可能會警告你; 你可能應該在列表中收集返回的值,並等待results = await asyncio.gather(*tasks)
。 這不僅會收集結果,還會確保在線程外函數中發生的異常正確傳播到您的代碼而不是丟棄。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.