如何在退出时使用kill在单独的线程中运行外部应用程序

时间:2018-11-08 13:03:48

标签: python multithreading python-asyncio

我现在被困了一些,想问也许有人遇到类似的问题。

启动应用程序时,我需要启动外部可执行文件,它必须一直存在,并且在应用程序退出时会死掉。但是因为加载需要花费很多时间,所以我想实时捕获输出并等待统计信息。

现在有趣的部分:

async def start_app(event):
    command_raw = 'ping 127.0.0.1'
    command = shlex.split(command_raw, posix="win" not in sys.platform)
    create = asyncio.create_subprocess_exec(*command, stdout=asyncio.subprocess.PIPE)
    proc = await create

    while True:
        data = await proc.stdout.readline()
        line = data.decode('ascii').rstrip()
        if line == 'Ping statistics for 127.0.0.1:':
            break
    event.set()


def runner_worker(runner_loop):
    asyncio.set_event_loop(runner_loop)
    runner_loop.run_forever()

if sys.platform == "win32":
    runner_loop = asyncio.ProactorEventLoop()

event = Event()
t = Thread(target=runner_worker, args=(runner_loop,))
t.start()

f = functools.partial(start_app, event)
runner_loop.call_soon_threadsafe(f)

print('waiting for externall app to start')
event.wait(timeout=60)
print('reasuming application')
time.sleep(2)

print('ending...')

如您所见,我希望阻塞循环在不同的线程中运行(该线程将始终被阻塞),从而设置了该应用程序已启动的标志。 在这里,我什至不确定这种方法是否正确。

即使忽略了我得到的错误:

RuntimeWarning: coroutine 'start_app' was never awaited
  self._callback(*self._args)

今天我尝试了不同的方法:

import asyncio
import concurrent.futures
import logging
import sys
import time
import shlex
import subprocess


def start_app_syn():
    log = logging.getLogger('ext application')
    log.info('starting application')
    command_raw = 'ping -t 127.0.0.1'
    command = shlex.split(command_raw, posix="win" not in sys.platform)
    proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
    while True:
        line = proc.stdout.readline().rstrip()
        if line == b'Reply from 127.0.0.1: bytes=32 time<1ms TTL=128':
            break
    return proc


async def run_blocking_tasks(executor):
    log = logging.getLogger('run_blocking_tasks')
    log.info('starting')

    log.info('creating executor ')
    loop = asyncio.get_event_loop()

    log.info('waiting for application start')
    runner = loop.run_in_executor(executor, start_app_syn, )
    try:
        proc = await asyncio.wait_for(runner, timeout=60)
        log.info('application has started')
    except TimeoutError as e:
        log.error('Process didnot started in acceptable time')
        raise e
    return proc


if __name__ == '__main__':
    logging.basicConfig(
        level=logging.INFO,
        format='%(threadName)10s %(name)18s: %(message)s',
        stream=sys.stderr,
    )

    executor = concurrent.futures.ThreadPoolExecutor()
    event_loop = asyncio.get_event_loop()
    task = asyncio.ensure_future(run_blocking_tasks(executor), loop=event_loop)
    proc = event_loop.run_until_complete(task)

    print('App started')
    print('doing a lot of stuff')
    for i in range(5):
        print('... ')
        time.sleep(1)

    print('Exiting...')
    proc.kill()
    event_loop.close()

有效。但是我无法判断这种好方法。

1 个答案:

答案 0 :(得分:0)

为什么不使用守护程序?如果主应用程序结束,将导致线程被杀死

...
t.daemon = True
t.start()