Как узнать, асинхронно определить, если подпроцесс asyn c завершен - PullRequest
2 голосов
/ 19 февраля 2020

Я пытаюсь использовать asyncio.create_subprocess_exec для запуска долго выполняющегося процесса (вроде демона).

Однако я не могу дождаться, чтобы узнать, был ли процесс успешным / неудачным. Я должен асинхронно определить, произошел ли сбой процесса, и обработать его в этот момент. В противном случае я оставляю демон подпроцесса включенным и связываюсь с ним по TCP / IP.

Я мог бы использовать обработчик сигнала в SIGCHLD, но есть ли в asyncio встроенные функции для создания обработчика для подпроцесса?

import asyncio
import subprocess

async def main():
    command = ["./some-long-running-daemon"]
    process = await asyncio.create_subprocess_exec(*command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print(process.returncode) # this is None

if __name__ == "__main__":
    asyncio.run(main())

Я обнаружил, что асинхронный подпроцесс c create, похоже, не совсем хорошо работает с SIGCHILD (обработчик даже не запускается). В то время как subprocess.Popen делает. У Popen также есть метод poll(), тогда как у подпроцесса asyn c нет. Кажется, Popen - это то, что нужно.

1 Ответ

4 голосов
/ 19 февраля 2020

Если вы счастливы написать обработчик сигнала, почему бы просто не создать новую задачу, которая ожидает завершения процесса до sh? После этого вы можете продолжать выполнять свою основную задачу так, как вам хочется.

import asyncio
import subprocess

async def child_done(proc):
    stdout, stderr = await proc.communicate()
    print('child done. output:', stdout, '-- return code was:', proc.returncode)

async def main():
    proc = await asyncio.create_subprocess_exec('ls', stdout=subprocess.PIPE)
    asyncio.create_task(child_done(proc))
    # do other stuff
    await asyncio.sleep(1)
    print('main done')

if __name__ == '__main__':
    asyncio.run(main())

Что дает вам вывод, такой как:

child done. output: b'asyncio-test.py\n' -- return code was: 0
main done
...