【问题标题】:Pythonic way to detach a process?Pythonic 分离进程的方法?
【发布时间】:2015-08-11 17:12:54
【问题描述】:

我正在运行一个etcd 进程,它会一直保持活动状态,直到您将其杀死。 (它不提供守护程序模式选项。)我想将其分离,以便继续运行更多 python。

我会在 shell 中做什么;

etcd & next_cmd

在整个互联网的热情推荐下,我正在使用python的sh库。我宁愿不使用subprocessPopen,但我也没有找到使用这些的解决方案。

我想要什么;

sh.etcd(detach=True)
sh.next_cmd()

sh.etcd("&")
sh.next_cmd()

不幸的是,detach 不是 kwarg,sh"&" 视为 etcd 的标志。

我在这里遗漏了什么吗?这样做的好方法是什么?

【问题讨论】:

    标签: python subprocess detach etcd


    【解决方案1】:

    subprocess 也很容易做到这一点:

    这种方法有效(python3)。关键是使用“start_new_session=True”

    更新:尽管 Popen 文档说这有效,但事实并非如此。我通过 fork 孩子然后做 os.setsid() 发现它可以按我的意愿工作

    client.py:

    #!/usr/bin/env python3
    import time
    import subprocess
    subprocess.Popen("python3 child.py", shell=True, start_new_session=True)
    i = 0
    while True:
        i += 1
        print("demon: %d" % i)
        time.sleep(1)
    

    child.py:

    #!/usr/bin/env python3
    import time
    import subprocess
    import os
    
    pid = os.fork()
    if (pid == 0):
        os.setsid()
    
        i = 0
        while True:
            i += 1
            print("child: %d" % i)
            time.sleep(1)
            if i == 10:
                print("child exiting")
                break
    

    输出:

    ./client.py
    demon: 1
    child: 1
    demon: 2
    child: 2
    ^CTraceback (most recent call last):
      File "./client.py", line 9, in <module>
        time.sleep(1)
    KeyboardInterrupt
    
    $ child: 3
    child: 4
    child: 5
    child: 6
    child: 7
    child: 8
    child: 9
    child: 10
    child exiting
    

    【讨论】:

    • 看起来你在所有类似的 stackoverflow 问题中复制粘贴了这个答案,但它不正确 - 它不会将子进程与其父进程分离,它只是创建一个子进程(在 linux,python 3.8 上)
    • 有点困惑,因为 Popen 文档说“如果 start_new_session 为真,则将在子进程执行之前在子进程中进行 setsid() 系统调用。(仅限 POSIX)”和“setsid () 库函数允许进程将自己与其父进程解除关联:"。所以它“应该”起作用。诚然,我在mac上测试过。好的,我需要检查...
    • 你是对的......好吧,我找到了一种解决方法,方法是再次分叉子项并执行 os.setsid。这似乎行得通——你能确认一下吗?这听起来确实像一个 Popen 错误,正如我在很多地方看到的那样“从 Python 3.2 开始,您可以使用 subprocess.Popen() 并传递 start_new_session=True 来完成子进程与父进程的完全分离。”
    【解决方案2】:

    如果没有其他原因,除了下次我用谷歌搜索同样的问题时发现它:

     if os.fork() == 0:
        os.close(0)
        os.close(1)
        os.close(2)
        subprocess.Popen(('etcd'),close_fds=True)
        sys.exit(0)
    

    popen close_fds 会关闭 0,1,2 以外的文件描述符,因此代码会显式关闭它们。

    【讨论】:

      【解决方案3】:

      这里是 sh 的作者。相信你要使用_bg特殊关键字参数http://amoffat.github.io/sh/#background-processes

      这将分叉您的命令并立即返回。即使您的脚本退出,该进程仍将继续运行。

      【讨论】:

        【解决方案4】:

        要实现sh&amp;,避免货物崇拜编程,直接使用subprocess模块:

        import subprocess
        
        etcd = subprocess.Popen('etcd') # continue immediately
        next_cmd_returncode = subprocess.call('next_cmd') # wait for it
        # ... run more python here ...
        etcd.terminate() 
        etcd.wait()
        

        这忽略了异常处理和您关于“守护程序模式”的讨论(如果您想在 Python 中实现守护程序;请使用python-daemon。要将进程作为系统服务运行,请使用您的操作系统提供的任何内容或主管程序,例如如supervisord)。

        【讨论】:

        【解决方案5】:

        请注意,在以下两个示例中,调用 time.sleep(...)etcd 时间在我们之前完成启动 向它发送请求。一个真正的解决方案可能涉及探测 API 端点以查看它是否可用,如果不可用则循环。

        选项 1(滥用multiprocessing 模块):

        import sh
        import requests
        import time
        
        from multiprocessing import Process
        
        etcd = Process(target=sh.etcd)
        
        try:
            # start etcd
            etcd.start()
            time.sleep(3)
        
            # do other stuff
            r = requests.get('http://localhost:4001/v2/keys/')
            print r.text
        finally:
            etcd.terminate()
        

        这使用multiprocessing 模块来处理 产生一个后台任务。使用这个模型,你不会看到 来自etcd 的输出。

        选项 2(经过验证):

        import os
        import signal
        import time
        import requests
        
        pid = os.fork()
        if pid == 0:
            # start etcd
            os.execvp('etcd', ['etcd'])
        
        try:
            # do other stuff
            time.sleep(3)
            r = requests.get('http://localhost:4001/v2/keys/')
            print r.text
        finally:
            os.kill(pid, signal.SIGTERM)
        

        这使用了传统的forkexec 模型,其工作原理与 在 Python 中就像在 C 中一样。在这个模型中,etcd 的输出 将显示在您的控制台上,这可能是也可能不是您想要的。您可以通过在子进程中重定向stdoutstderr 来控制。

        【讨论】:

        猜你喜欢
        • 2013-10-01
        • 1970-01-01
        • 2016-06-27
        • 1970-01-01
        • 1970-01-01
        • 2021-02-26
        • 1970-01-01
        • 2014-06-13
        • 1970-01-01
        相关资源
        最近更新 更多