Pythonic分离进程的方法?

时间:2015-05-29 00:43:23

标签: python subprocess detach etcd

我正在运行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的标志。

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

5 个答案:

答案 0 :(得分:6)

要实施sh的{​​{1}},请避免货物编程并直接使用&模块:

subprocess

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

答案 1 :(得分:4)

sh的作者。我相信您想使用_bg特殊关键字参数http://amoffat.github.io/sh/#background-processes

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

答案 2 :(得分:1)

请注意以下两个示例中有一个调用 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来控制此操作。

答案 3 :(得分:0)

子进程也很容易做到这一点:

这种方法有效(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

答案 4 :(得分:-1)

如果除了我下次搜索相同问题时没有其他原因而发布此信息:

 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以外的文件描述符,因此代码显式关闭它们。