【问题标题】:Non blocking subprocess.call非阻塞 subprocess.call
【发布时间】:2013-04-10 21:55:24
【问题描述】:

我正在尝试进行非阻塞子进程调用以从我的 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 进行通信的某个点上,而我目前不需要。有谁知道如何以简单的方式实现这个......?

【问题讨论】:

    标签: python subprocess


    【解决方案1】:

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

    类似:

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

    来自docs on subprocess.call

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

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


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

    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在 OS-X 上使用 python2.7 和 python3.6 测试

    【讨论】:

    • 谢谢,这似乎可行,但是当我在 slave.py 中包含一个 While 循环时,它似乎被卡住并且在循环中没有执行任何操作(即使使用 timer.sleep() 函数..?
    • @mgilson:您能否分享一个有关如何使用它的一般示例?我的意思是当以非阻塞方式使用它时,控制流应该是什么样子。我很感激。
    • @ViFI -- 当然,我添加了一个以非阻塞方式使用 Popen 的示例。
    • 有没有办法像p1 & p2 & 那样异步启动多个进程,然后使用asyncio 等待所有进程?我希望这不需要多处理模块。
    • 当然,您只需要一个do_p1 函数和一个do_p2 函数,然后将它们都添加到tasks 列表中。
    【解决方案2】:

    这里的彻底性分为三个级别。

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

    【讨论】:

      【解决方案3】:

      对于 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 上测试

      【讨论】:

        猜你喜欢
        • 2016-01-04
        • 2016-07-06
        • 1970-01-01
        • 1970-01-01
        • 2012-11-13
        • 1970-01-01
        相关资源
        最近更新 更多