私は、Python asyncio
モジュール(Linux上)を使用して子プロセスを起動し、それを非同期に監視しています。私のコードは正常に動作します... メインスレッドで実行すると。しかし、ワーカースレッド上で実行すると、ハングアップし、process_exited
コールバックは呼び出されません。Python asyncio:ワーカースレッドでsubprocess_execを実行する
ワーカースレッドでsubprocess_exec
を実行すると、文書化されていない不具合や問題が発生している可能性があります。バックグラウンドスレッドの実装の実装方法と関係している可能性があります。しかし、それは私だけものを台無しにするかもしれない。
簡単、次のように再現可能な例である:シェルコマンドls -lh
を実行し、データをサブプロセスから受信されたときのコールバックをトリガーする
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()
だからここで、Iセットアップasyncio
イベントループ、サブプロセスが終了したときの別のコールバック。
私がPythonプログラムのメインスレッドで直接run_loop()
を呼び出すと、すべてうまく行きます。しかし、私は言った場合:
t = threading.Thread(target = run_loop)
t.start()
t.join()
は、次に何が起こるかpipe_data_received()
コールバックが正常に起動されますが、process_exited()
が呼び出されることはありませんし、プログラムがハングしていることです。
次のように周りのグーグルとunix_events.py
の実施のためのasyncio
ソースコードを見た後、私は、それを手動でグローバルな「子ウォッチャー」オブジェクトに私のイベントループを取り付ける必要があるかもしれない発見:
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
モジュールは非常に実証されていないので、私の結論はここでは確信できません。私は単に何かが間違っている可能性があります。インスタンス化ワーカースレッドでサブプロセスの処理