如何从 Python 异步调用 shell 脚本?

How to asynchronously call a shell script from Python?

我有一个 shell 脚本,它对传递的字符串进行一些处理,然后将其写入文件。但是我不希望我的函数 foo() 等待它完成操作。如何调用 process(msg) 然后继续执行 {code block 2} 而无需等待 process(msg) 完成执行?

def process(msg):
    subprocess.call(['sh', './process.sh', msg])

def foo():
    # {code block 1}
    process(msg)
    # {code block 2}

foo() 将被另一个函数调用,几乎每秒一到两次。

subprocess.call() 和 subprocess.run() 创建一个进程,等待它完成,然后 returns 一个 CompletedProcess 对象。

subprocess.Popen() 创建一个进程并 returns 它。它在以前的功能的幕后使用。然后,您可以等待该过程完成、向其发送消息或进行任何您想对其进行的操作。参数 mos 与 callrun.

完全相同

https://docs.python.org/3/library/subprocess.html

更详细地说,Popen 是使用 os 启动新进程的 python 实现。 os.fork() 是一个较低的层次,它实际上并没有做我们在这里想要做的事情,它会产生另一个 python 解释器的实例,其内存状态与当前解释器相同。如果您想使用较低级别的系统调用,os.spawnos.fork.

更接近 subprocess.run subprocess.run

为了验证 Popen 正在做你想要的,这个测试程序将弹出“returncode = None”,然后等待 5 秒,并打印“returncode = 0”

from subprocess import Popen

p = Popen(["sleep", "5"])
print("started the proc")  # this will print immediately
p.poll()  # this checks if the process is done but does not block
print(f"p returncode = {p.returncode}")
p.wait()  # this blocks until the process exits
print(f"p returncode = {p.returncode}")

您需要的是 https://docs.python.org/3/library/os.html#os.fork,即 os.fork() 这样您就可以生成一个比父进程寿命更长的子进程,该子进程稍后可以由 systemd 在 Linux 上声明.我不知道 Windows。

只是为了完整性:Python 的 asyncio 提供了一个高级接口来做这件事: https://docs.python.org/3.9/library/asyncio-subprocess.html#subprocesses

文档中的示例:

import asyncio

async def run(cmd):
    proc = await asyncio.create_subprocess_shell(
        cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE)

    stdout, stderr = await proc.communicate()

    print(f'[{cmd!r} exited with {proc.returncode}]')
    if stdout:
        print(f'[stdout]\n{stdout.decode()}')
    if stderr:
        print(f'[stderr]\n{stderr.decode()}')

asyncio.run(run('ls /zzz'))