这个答案与
此答案相关,并使用类似的机制(基于
select
系统调用)称为
asyncio
。您可以在
此处了解有关
asyncio
的更多信息。
当您的进程受IO限制时,
Asyncio
非常适用。至少在程序的这个部分中,您的进程似乎受到IO限制,大部分时间都在等待外部脚本完成,只有在它们结束时才打印一条消息。
以下代码应该适合您(可能需要进行一些小的调整):
import asyncio
runcodes = ["script1.C", "script2.C"]
async def run_script(script):
p = await asyncio.create_subprocess_exec(script)
await p.wait()
print("Script", script, "is done")
async def main():
tasks = []
for script in runcodes:
tasks.append(asyncio.create_task(run_script(script)))
for task in tasks:
await task
if __name__ == "__main__":
asyncio.run(main())
详细解释
Asyncio 可以让你通过交替各个异步任务并在它们都被阻塞时等待,来用单个线程执行并发任务。
run_script
函数是异步的,并且会使用类似于subprocess.Popen
的机制调用你的脚本。这里的区别是返回的对象是可等待的(awaitable),意味着当等待函数被阻塞时,你可以跳到别的地方。
你可以在这里了解更多关于使用 asyncio
管理子进程的内容。你会发现,处理子进程的方式与通常的 Python 子进程非常相似。Popen 的参数也很类似。
请注意,这与线程不同。事实上,这个程序是单线程的。不要混淆 asyncio 和多线程。它们是并发运行任务的两种不同方法(具有优缺点)。
主函数将创建多个任务,每个任务用于运行你想要运行的一个脚本,并等待它们完成。
重要的是,这个await
不会阻塞,同时它也不会进行实时轮询。它将休眠,直到任何一个任务准备就绪。一旦任务就绪,执行将返回到该任务,该任务可以打印有关你的消息的语句。
程序将不会退出主函数,直到所有等待的任务都完成。它将在由asyncio.run
生成的等待函数循环内保持,直到所有东西都完成。
mylongrunningproc
运行时,有没有办法让subproc.stdout
打印到终端? - unutbupoller.register(subproc.stdout, select.EPOLLHUP | select.EPOLLIN)
。然后你可以使用if flags & select.EPOLLIN: print done_proc.stdout.readline()
。但是,如果输出没有按行分隔符,则必须小心无限期阻塞的情况。在Linux中,我认为您可以通过使用fcntl
将stdout管道设置为非阻塞,并使用errno = EAGAIN捕获IOError来解决此问题。 示例 -fcntl.fcntl(subproc.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
。 - Jeremy Brown