简体   繁体   English

Asyncio 在 wait_for 超时时终止子进程

[英]Asyncio Terminate Subprocess on wait_for timeout

I have a long running process and its children (in this example it is stress ) that I wish to terminate after some time.我有一个长时间运行的进程及其子进程(在这个例子中是stress ),我希望在一段时间后终止。 I am using asyncio.wait_for since it's what the documentation suggests, but while the timeout occurs and the asyncio.TimeoutError is raised, the process is still running.我正在使用asyncio.wait_for因为它是文档所建议的,但是当发生超时并且引发asyncio.TimeoutError时,进程仍在运行。 I'm running on Python 3.8.10.我在 Python 3.8.10 上运行。

Here's my code:这是我的代码:

import asyncio

async def run(cmd):
    print("Running: ", cmd)

    proc = await asyncio.create_subprocess_exec(
        *cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE)

    stdout, stderr = await proc.communicate()
    stdout = stdout.decode('UTF-8')
    stderr = stderr.decode('UTF-8')
    
    return (stdout, stderr, proc.pid, proc.returncode)

async def run_with_timeout(cmd, timeout=20):
    task = asyncio.wait_for(run(cmd), timeout=timeout)
    
    try:
        output = await task
        stdout, _, pid, _ = output
        return str(stdout).strip()
    except asyncio.TimeoutError as e:
        print("Terminating Process '{0}' (timed out)".format(cmd))
        
asyncio.run(run_with_timeout(['stress', '--cpu', '2'], timeout=5))

Can someone suggest a way to kill this process after the timeout?有人可以建议一种在超时后终止此进程的方法吗? Thanks in advance: :D提前致谢

I ended up solving it by modifying the functions a bit.我最终通过稍微修改函数来解决它。 Before, my run() function returned the output of the command.之前,我的run() function 返回了命令的output。 By returning the process proc , I could monitor the timeout for the proc.communicate() .通过返回进程proc ,我可以监控proc.communicate()的超时。 This is the portion that waits until the process is done.这是等待过程完成的部分。 If the process takes longer than timeout , then I ask if it is done, by looking into proc.returncode .如果该过程花费的时间超过timeout ,那么我会通过查看proc.returncode询问它是否完成。 If it is other than None it has finished.如果它不是None则它已经完成。 If it is None , then I recursively kill every child and finally the parent process itself.如果它是None ,那么我递归地杀死每个孩子,最后杀死父进程本身。

async def run(cmd):
    print("Running: ", cmd)

    proc = await asyncio.create_subprocess_exec(
        *cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE)

    return proc

async def run_with_timeout(cmd, timeout=20):
    proc = await run(cmd)

    try:
        output = await asyncio.wait_for(proc.communicate(), timeout=timeout)
        stdout, _ = output
        return str(stdout).strip()
    except asyncio.TimeoutError:
        if proc.returncode is None:
            parent = psutil.Process(proc.pid)
            for child in parent.children(recursive=True): 
                child.terminate()
            parent.terminate()
            print("Terminating Process '{0}' (timed out)".format(cmd))
        
        
asyncio.run(run_with_timeout(['stress', '--cpu', '2'], timeout=5))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM