62

我正在尝试进行非阻塞子进程调用以从我的 main.py 程序运行 slave.py 脚本。我需要将 args 从 main.py 传递给 slave.py 一次,当它(slave.py)第一次通过 subprocess.call 启动时,这个 slave.py 运行一段时间然后退出。

main.py
for insert, (list) in enumerate(list, start =1):

    sys.args = [list]
    subprocess.call(["python", "slave.py", sys.args], shell = True)


{loop through program and do more stuff..}

还有我的奴隶脚本

slave.py
print sys.args
while True:
    {do stuff with args in loop till finished}
    time.sleep(30)

目前,slave.py 阻止 main.py 运行其其余任务,我只是希望 slave.py 独立于 main.py,一旦我将 args 传递给它。这两个脚本不再需要通信。

我在网上找到了一些关于非阻塞 subprocess.call 的帖子,但其中大部分都集中在需要与 slave.py 进行通信的某个点上,而我目前不需要。有谁知道如何以简单的方式实现这个......?

4

3 回答 3

67

您应该使用subprocess.Popen而不是subprocess.call.

就像是:

subprocess.Popen(["python", "slave.py"] + sys.argv[1:])

从上的文档subprocess.call

运行 args 描述的命令。等待命令完成,然后返回 returncode 属性。

(如果您要使用 ,也不要使用列表来传递参数shell = True)。


这是一个演示非阻塞 suprocess 调用的 MCVE 1示例:

import subprocess
import time

p = subprocess.Popen(['sleep', '5'])

while p.poll() is None:
    print('Still sleeping')
    time.sleep(1)

print('Not sleeping any longer.  Exited with returncode %d' % p.returncode)

另一种依赖于 python 语言的最新更改以允许基于协同程序的并行性的替代方法是:

# python3.5 required but could be modified to work with python3.4.
import asyncio

async def do_subprocess():
    print('Subprocess sleeping')
    proc = await asyncio.create_subprocess_exec('sleep', '5')
    returncode = await proc.wait()
    print('Subprocess done sleeping.  Return code = %d' % returncode)

async def sleep_report(number):
    for i in range(number + 1):
        print('Slept for %d seconds' % i)
        await asyncio.sleep(1)

loop = asyncio.get_event_loop()

tasks = [
    asyncio.ensure_future(do_subprocess()),
    asyncio.ensure_future(sleep_report(5)),
]

loop.run_until_complete(asyncio.gather(*tasks))
loop.close()

1使用 python2.7 & python3.6 在 OS-X 上测试

于 2013-04-17T23:17:03.547 回答
29

这里有三个层次的彻底性。

正如 mgilson 所说,如果您只是换掉subprocess.callsubprocess.Popen保持其他所有内容相同,那么 main.py 将不会等待 slave.py 完成后再继续。这本身可能就足够了。如果您关心挂起的僵尸进程subprocess.Popen,您应该保存从返回的对象,并在稍后调用它的wait方法。(当 main.py 退出时僵尸会自动消失,所以如果 main.py 运行很长时间和/或可能创建许多子进程,这只是一个严重的问题。)最后,如果你不想要僵尸但是您也不想决定在哪里进行等待(如果两个进程随后运行了很长时间且不可预测的时间,这可能是合适的),请使用python-daemon库让从站与主站解除关联——在这种情况下,您可以继续subprocess.call在主站中使用。

于 2013-04-17T23:21:29.620 回答
2

对于 Python 3.8.x

import shlex
import subprocess

cmd = "<full filepath plus arguments of child process>"
cmds = shlex.split(cmd)
p = subprocess.Popen(cmds, start_new_session=True)

这将允许父进程退出,而子进程继续运行。不确定僵尸。

在 macOS 10.15.5 上的 Python 3.8.1 上测试

于 2020-09-30T20:39:24.427 回答