5

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

我会在 shell 中做什么;

etcd & next_cmd

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

我想要的是;

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

或者

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

不幸detach的是,它不是一个 kwarg,而是sh将."&"etcd

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

4

5 回答 5

7

要实现sh's &,避免货物崇拜编程并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)。

于 2015-05-29T08:43:59.410 回答
4

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

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

于 2015-05-30T18:21:57.907 回答
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)

这使用了传统的forkandexec模型,它在 Python 中的效果与在 C 中一样好。在此模型中, 的输出etcd 将显示在您的控制台上,这可能是也可能不是您想要的。您可以通过重定向stdoutstderr在子进程中来控制它。

于 2015-05-29T01:24:33.613 回答
1

subprocess 也很容易做到这一点:

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

更新:尽管 Popen 文档说这有效,但它没有。我通过分叉孩子然后做 os.setsid() 发现它可以按我的意愿工作

客户端.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)

孩子.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
于 2021-01-26T11:18:22.973 回答
-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 以外的文件描述符,因此代码显式关闭它们。

于 2020-07-31T21:33:28.907 回答