在一个时间间隔内使用 asyncio to 运行 命令并在之后终止它

Using asyncio to run command in a time interval and terminate it afterwards

我正在执行 os.system() 的 shell 命令。我计划 运行 它 1 秒,然后在超过时间时终止它。这是我作为测试尝试的内容。

import os, time, asyncio

async def cmd():
    os.system("my.py > my.txt") # this processes longer than 1 second

@asyncio.coroutine
def run():
    try:
        yield from asyncio.wait_for(cmd(), 1) # this should excute for more than 1 sec, and hence raise TimeoutError
        print("A")
    except asyncio.TimeoutError:
        os.system("killall python")
        print("B")
    
asyncio.run(run())

但结果总是“A”,txt 是 my.py 写的。

我也试过:

import os, time, asyncio

async def cmd():
    os.system("my.py > my.txt") # longer than 1 sec

async def run():
    try:
        await asyncio.wait_for(cmd(), 1) # should raise TimeoutError
        print("A")
    except asyncio.TimeoutError:
        os.system("killall python")
        print("B")
    
asyncio.run(run())

结果相同。 代码有什么问题?我对 asyncio 很陌生,以前从未使用过它。提前致谢。 wait_for 不会自动停止转换很可能不是问题,因为我在第二部分有一个 killall python 事实上,wait_for 函数永远不会引发超时错误,那是问题。

os.system是阻塞操作,所以和asyncio玩起来不太好。每当您使用 asyncio 时,所有“更长”的操作都需要是异步的,否则您首先会失去使用 asyncio 的所有好处。

import asyncio

async def cmd():
    try:
        proc = await asyncio.create_subprocess_shell(
            "sleep 2 && date > my.txt",
            shell=True,
            stdout=asyncio.subprocess.DEVNULL,
            stderr=asyncio.subprocess.DEVNULL)
        await proc.communicate()

    except asyncio.CancelledError:
        proc.terminate()
        print("X")

async def run():
    try:
        await asyncio.wait_for(cmd(), 1)
        print("A")

    except asyncio.TimeoutError:
        print("B")

asyncio.run(run())

正如@dim 在评论中提到的,asyncio.create_subprocess_exec 将异步启动外部命令。 wait_for 实际上会引发两个异常:等待代码中的 TimeoutError 和等待代码中的 CancelledError。我们可以使用后者来实现操作被取消,并terminatekill我们的子进程(因为这不是自动完成的)。