【问题标题】:How to gracefully timeout with asyncio如何使用 asyncio 优雅地超时
【发布时间】:2018-01-07 15:57:24
【问题描述】:

因此,在添加 try/catch 块之前,当进程运行不到 5 分钟时,我的事件循环会正常关闭,但在添加 try/catch 块后,当进程超过 5 分钟时,我开始收到此错误

async def run_check(shell_command):
    p = await asyncio.create_subprocess_shell(shell_command,
                    stdin=PIPE, stdout=PIPE, stderr=STDOUT)
    fut = p.communicate()
    try:
        pcap_run = await asyncio.wait_for(fut, timeout=5)
    except asyncio.TimeoutError:
        pass

def get_coros():
    for pcap_loc in print_dir_cointent():
        for pcap_check in get_pcap_executables():
            tmp_coro = (run_check('{args}'
            .format(e=sys.executable, args=args)))
            if tmp_coro != False:
                coros.append(tmp_coro)
     return coros

async def main(self):
    p_coros = get_coros()
    for f in asyncio.as_completed(p_coros):
        res = await f




loop = asyncio.get_event_loop()
loop.run_until_complete(get_coros())
loop.close()

追溯:

Exception ignored in: <bound method BaseSubprocessTransport.__del__ of 
    <_UnixSubprocessTransport closed pid=171106 running stdin=
    <_UnixWritePipeTransport closing fd=8 open> stdout=<_UnixReadPipeTransport fd=9 open>>>
    Traceback (most recent call last):
      File "/usr/lib/python3.5/asyncio/base_subprocess.py", line 126, in __del__
      File "/usr/lib/python3.5/asyncio/base_subprocess.py", line 101, in close
      File "/usr/lib/python3.5/asyncio/unix_events.py", line 568, in close
      File "/usr/lib/python3.5/asyncio/unix_events.py", line 560, in write_eof
      File "/usr/lib/python3.5/asyncio/base_events.py", line 497, in call_soon
      File "/usr/lib/python3.5/asyncio/base_events.py", line 506, in _call_soon
      File "/usr/lib/python3.5/asyncio/base_events.py", line 334, in _check_closed
    RuntimeError: Event loop is closed

回溯发生在我的代码的最后一行执行之后。

调试日志:

DEBUG:asyncio:Using selector: EpollSelector
DEBUG:asyncio:run shell command '/local/p_check w_1.pcap --json' stdin=<pipe> stdout=stderr=<pipe>
DEBUG:asyncio:process '/local/p_check w_1.pcap --json' created: pid 171289DEBUG:asyncio:Write pipe 8 connected: (<_UnixWritePipeTransport fd=8 idle bufsize=0>, <WriteSubprocessPipeProto fd=0 pipe=<_UnixWritePipeTransport fd=8 idle bufsize=0>>)
DEBUG:asyncio:Read pipe 9 connected: (<_UnixReadPipeTransport fd=9 polling>, <ReadSubprocessPipeProto fd=1 pipe=<_UnixReadPipeTransport fd=9 polling>>) INFO:asyncio:run shell command '/local/p_check w_1.pcap --json': <_UnixSubprocessTransport pid=171289 running stdin=<_UnixWritePipeTransport fd=8 idle bufsize=0> stdout=<_UnixReadPipeTransport fd=9 polling>>
DEBUG:asyncio:<Process 171289> communicate: read stdout
INFO:asyncio:poll 4997.268 ms took 5003.093 ms: timeout
DEBUG:asyncio:Close <_UnixSelectorEventLoop running=False closed=False debug=True>

【问题讨论】:

    标签: python-3.x async-await runtime-error python-asyncio timeoutexception


    【解决方案1】:

    loop.run_until_complete 接受等待的东西:协程或未来。您传递什么都不返回的函数的结果。

    您应该更改 get_coros() 以实际返回 coros 列表:

    def get_coros():
        ...
        return coros
    

    然后将该列表转换为可等待的,以逐个执行作业(如果您愿意,也可以并行执行)。例如:

    async def main():
        for coro in get_coros():
            await coro
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()
    

    更新:

    我现在无法测试我的猜测,但它是:虽然asyncio.wait_for(fut, timeout=5) 在 5 秒后取消任务,但它不会 terminate 进程。您可以手动执行此操作:

    try:
        await asyncio.wait_for(fut, timeout=5)
    except asyncio.TimeoutError:
        p.kill()
        await p.communicate()
    

    【讨论】:

    • 更新了上面的代码,我得到了同样的错误,只是当我循环进入 main() w/o asyncio.as_completed 我得到这个 [ERROR ] 任务被破坏,但它正在等待处理!
    • 完美。谢谢。
    • 在我的代码中,我在 asyncio.wait 中使用了超时。它会导致等待函数在超时后return,not 抛出超时错误。挂起的作业(由 asyncio.wait 返回)可以再次重新添加,并将正常继续。 “取消”任务完全不同。
    • @YtsendeBoer documentation 明确指出:“如果发生超时,它会取消任务并引发 asyncio.TimeoutError”。您可能将asyncio.wait_for 与asyncio.wait 混淆了。最后一个behaves 就像你说的,但与这个答案无关。
    • 好吧,我现在正在查看我的代码,正如我告诉你的那样:) 就像一个魅力。但你是对的,除此之外,对不起。
    猜你喜欢
    • 1970-01-01
    • 2015-03-05
    • 2016-09-21
    • 2018-11-25
    • 2013-10-17
    • 2011-11-26
    • 2011-05-23
    • 2019-01-15
    • 1970-01-01
    相关资源
    最近更新 更多