簡體   English   中英

Python asyncio:在輔助線程上運行subprocess_exec

[英]Python asyncio: Running subprocess_exec on a worker thread

因此,我正在使用Python asyncio模塊(在Linux上)啟動子進程,然后對其進行異步監視。 我的代碼在主線程上運行時工作正常。 但是,當我在輔助線程上運行它時,它將掛起,並且永遠不會調用process_exited回調。

我懷疑這實際上可能是某種未記錄的缺陷,或者是在工作線程上運行subprocess_exec問題,可能與實現如何處理后台線程中的信號有關。 但這也可能只是我搞砸了。

一個簡單的,可復制的示例如下:

class MyProtocol(asyncio.SubprocessProtocol):
    def __init__(self, done_future):
        super().__init__()
        self._done_future = done_future

    def pipe_data_received(self, fd, data):
        print("Received:", len(data))

    def process_exited(self):
        print("PROCESS EXITED!")
        self._done_future.set_result(None)

def run(loop):
    done_future = asyncio.Future(loop = loop)
    transport = None
    try:
        transport, protocol = yield from loop.subprocess_exec(
            lambda : MyProtocol(done_future),
            "ls",
            "-lh",
            stdin = None
        )
        yield from done_future
    finally:
        if transport: transport.close()

    return done_future.result()

def run_loop():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop) # bind event loop to current thread

    try:
        return loop.run_until_complete(run(loop))
    finally:
        loop.close()

因此,在這里,我設置了一個asyncio事件循環來執行shell命令ls -lh ,然后為從子流程接收到數據時觸發一個回調,為子流程退出時觸發另一個回調。

如果我只是直接在Python程序的主線程中調用run_loop() ,那么一切都會順利進行。 但是如果我說:

t = threading.Thread(target = run_loop)
t.start()
t.join()

然后發生的事情是成功調用了pipe_data_received()回調,但是從未調用過process_exited() ,並且程序僅掛起。

在四處asyncio並查看了asyncio的實現的asyncio源代碼unix_events.py ,我發現可能有必要將事件循環手動附加到全局“ child watcher”對象,如下所示:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop) # bind event loop to current thread
asyncio.get_child_watcher().attach_loop(loop)

顯然,兒童觀察者是一個(未記錄的)對象,負責在內部調用waitpid (或類似的東西)。 但是,當我嘗試這樣做並在后台線程中運行run_event_loop()時,出現了錯誤:

  File "/usr/lib/python3.4/asyncio/unix_events.py", line 77, in add_signal_handler
    raise RuntimeError(str(exc))
RuntimeError: set_wakeup_fd only works in main thread

因此,這里看起來該實現實際上進行了檢查,以確保只能在主線程上使用信號處理程序,這使我相信,在當前實現中,實際上在后台線程上使用subprocess_exec是完全不可能的,而無需更改Python源代碼本身。

我對此是否正確? 可悲的是, asyncio模塊的文檔非常少,所以我很難對這里的結論充滿信心。 我可能做錯了什么。

只要在主線程中運行asyncio循環且其子監視程序實例化,就可以在輔助線程中處理子進程:

asyncio.get_child_watcher()
loop = asyncio.get_event_loop()
coro = loop.run_in_executor(None, run_loop)
loop.run_until_complete(coro)

請參閱這篇文章文檔

暫無
暫無

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

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