子进程在使用多处理时不考虑参数

Subprocess doesn't respect arguments when using multiprocessing

这里的主要 objective 是创建守护进程生成函数。守护进程需要 运行 任意程序(即使用 subprocess)。

到目前为止,我的 daemonizer.py 模块中的内容是:

import os
from multiprocessing import Process
from time import sleep
from subprocess import call, STDOUT


def _daemon_process(path_to_exec, std_out_path, args, shell):

    with open(std_out_path, 'w') as fh:
        args = (str(a) for a in args)

        if shell:
            fh.write("*** LAUNCHING IN SHELL: {0} ***\n\n".format(" ".join([path_to_exec] + list(args))))
            retcode = call(" ".join([path_to_exec] + list(args)), stderr=STDOUT, stdout=fh, shell=True)
        else:
            fh.write("*** LAUNCHING WITHOUT SHELL: {0} ***\n\n".format([path_to_exec] + list(args)))
            retcode = call([path_to_exec] + list(args), stderr=STDOUT, stdout=fh, shell=False)

        if retcode:
            fh.write("\n*** DAEMON EXITED WITH CODE {0} ***\n".format(retcode))
        else:
            fh.write("\n*** DAEMON DONE ***\n")


def daemon(path_to_executable, std_out=os.devnull, daemon_args=tuple(), shell=True):

    d = Process(name='daemon', target=_daemon_process, args=(path_to_executable, std_out, daemon_args, shell))
    d.daemon = True
    d.start()

    sleep(1)

当在 bash 中尝试 运行 时(这将在您的当前目录中创建一个名为 test.log 的文件。):

python -c"import daemonizer;daemonizer.daemon('ping', std_out='test.log', daemon_args=('-c', '5', '192.168.1.1'), shell=True)"

它正确地生成了一个启动 ping 的守护进程,但它不遵守传递的参数。如果 shell 也设置为 False,也是如此。日志文件清楚地指出它试图用传递的参数启动它。

作为创建以下可执行文件的概念证明:

echo "ping -c 5 192.168.1.1" > ping_test
chmod +x ping_test

以下按预期工作:

python -c"import daemonizer;daemonizer.daemon('./ping_test', std_out='test.log', shell=True)"

如果我在 multiprocessing.Process-target 之外测试相同的 call 代码,它会按预期工作。

那么我该如何解决这个问题,以便我可以生成带参数的进程?

我对完全不同的结构和模块持开放态度,但它们应该包含在标准结构和模块中并与 python 2.7.x 兼容。要求是 daemon 函数应该可以在脚本中异步调用多次,并且每次都生成一个守护进程,并且它们的目标进程应该能够在不同的 CPU 上结束。当然,脚本也需要能够在不影响生成的守护进程的情况下结束。

作为奖励,我注意到我需要有一个 sleep 才能使生成工作,否则脚本终止得太快。有什么方法可以绕过这种任意攻击 and/or 我真的需要等多久才能安全?

你的论点被印刷出来"used up"!

首先,你这样做:

args = (str(a) for a in args)

创建生成器,而不是列表或元组。所以当你以后这样做时:

list(args)

这样就消耗了参数,不会再看到第二次了。所以你再做一次:

list(args)

并得到一个空列表!

您可以通过注释掉您的打印语句来解决此问题,但更好的方法是首先简单地创建一个列表:

args = [str(a) for a in args]

那你可以直接用args,不用list(args)。并且它始终包含参数。