簡體   English   中英

如何使用 ProcessPoolExecutor 和 asyncio 異步運行阻塞任務?

[英]How to run a blocking task asynchronously with ProcessPoolExecutor and asyncio?

我正在嘗試使用 ProcessPoolExecutor 異步運行阻塞任務(它與 ThreadPoolExecutor 一起使用,但我需要 ProcessPoolExecutor 來執行 CPU 綁定任務)。 這是我的代碼:


import asyncio
import time
from concurrent.futures import ProcessPoolExecutor
 
 
async def run_in_thread(task, *args):
    with ProcessPoolExecutor() as process_pool:
        loop = asyncio.get_event_loop()
        result = await loop.run_in_executor(process_pool, task, *args)
        return result
        
async def main_task():
    while True:
        await asyncio.sleep(1)
        print("ticker")

async def main():
    asyncio.create_task(main_task())

    global blocking_task
    def blocking_task():
        time.sleep(5)
        print("blocking task done!")
    await run_in_thread(blocking_task)
 
 
if __name__ == "__main__":
    asyncio.run(main())

我得到這個錯誤:

result = await loop.run_in_executor(process_pool, task, *args)
concurrent.futures.process.BrokenProcessPool: A process in the process pool was terminated abruptly while the future was running or pending.        

我不明白問題出在哪里,有人可以幫助我嗎? 我還想了解為什么它適用於 ThreadPoolExecutor 而不是 ProcessPoolExecutor

我期待代碼打印:

ticker
ticker
ticker
ticker
ticker
blocking task done!

將 blocking_task 的定義移動到模塊的外層。 正如腳本所示,此功能對其他進程不可見。 該函數的代碼不會直接發送給其他進程,只會發送其名稱 另一個進程執行自己單獨的腳本導入,但名稱未在頂層定義。

這與您嘗試將此腳本導入另一個腳本的邏輯相同。 假設此腳本位於名為 foo.py 的文件中。 在執行import foo之后,沒有名為foo.blocking_task的函數,因此您將無法調用它。

如果您查看整個回溯,而不僅僅是最后一行,這會更清楚一點。

順便說一句,在函數定義前面使用全局語句與將定義移到頂層不是一回事。 在您的腳本中,名稱blocking_task在 main() 函數實際運行之前在模塊級別不存在(輔助進程從不運行)。 在下面的工作腳本中,名稱blocking_task在導入模塊后立即存在。

import asyncio
import time
from concurrent.futures import ProcessPoolExecutor
 
 
async def run_in_thread(task, *args):
    with ProcessPoolExecutor() as process_pool:
        loop = asyncio.get_event_loop()
        result = await loop.run_in_executor(process_pool, task, *args)
        return result
        
async def main_task():
    while True:
        await asyncio.sleep(1)
        print("ticker")

def blocking_task():
    time.sleep(5)
    print("blocking task done!")
        
async def main():
    asyncio.create_task(main_task())
    await run_in_thread(blocking_task)
 
if __name__ == "__main__":
    asyncio.run(main())

這將打印出您所期望的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM