使用多处理时,子流程不尊重参数

时间:2016-06-21 12:15:50

标签: python linux multithreading bash subprocess

这里的主要目标是创建一个守护进程 - 产生函数。守护进程需要运行任意程序(即使用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,则为true。日志文件明确指出它试图通过传递的参数启动它。

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

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)"

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

那么如何修复这个混乱以便我可以使用参数生成进程?

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

作为奖励,我注意到我需要有一个sleep产卵才能在脚本终止太快的情况下工作。有什么方法可以解决这个任意黑客攻击和/或我需要多长时间让它等待安全?

1 个答案:

答案 0 :(得分:2)

你的论点正在被用完"通过印刷它们!

首先,你这样做:

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

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

list(args)

消耗这些论点,他们不会第二次看到它们。所以你再次这样做:

list(args)

获得一个空列表!

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

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

然后您可以直接使用args而不是list(args)。而且它总会有内在的论点。