分离进程的Pythonic方式?
Pythonic way to detach a process?
我是 运行 一个 etcd
进程,在您终止它之前它一直处于活动状态。 (它不提供守护进程模式选项。)我想分离它以便我可以保留 运行 更多 python.
我会在 shell;
做什么
etcd & next_cmd
我正在使用 python 的 sh
库,受到整个互联网的热烈推荐。我不想深入研究 subprocess
或 Popen
,但我也没有找到使用它们的解决方案。
我想要的;
sh.etcd(detach=True)
sh.next_cmd()
或
sh.etcd("&")
sh.next_cmd()
不幸的是 detach
不是 kwarg 并且 sh
将 "&"
视为 etcd
的标志。
我在这里遗漏了什么吗?这样做的好方法是什么?
请注意,在以下两个示例中调用了
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)
这使用传统的 fork
和 exec
模型,其工作方式与
在 Python 中很好,就像在 C 中一样。在这个模型中,etcd
的输出
将显示在您的控制台上,这可能是您想要的,也可能不是您想要的。您可以通过在子进程中重定向 stdout
和 stderr
来控制它。
要实现 sh
的 &
,避免 cargo cult 编程并直接使用 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()
这会忽略异常处理和您关于 "daemon mode" 的讨论(如果您想在 Python 中实现守护进程;请使用 python-daemon. To run a process as a system service, use whatever your OS provides or a supervisor program such as supervisord
)。
这里是 sh 的作者。我相信你想使用 _bg
特殊关键字参数 http://amoffat.github.io/sh/#background-processes
这将立即分叉您的命令和 return。即使在您的脚本退出后,该过程仍将继续 运行。
如果下次我 google 同样的问题时发现它,没有其他原因就发布这个:
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 以外的文件描述符,因此代码明确关闭它们。
子流程也很容易做到这一点:
这种方法有效 (python3)。关键是使用“start_new_session=True”
更新:尽管 Popen 文档说这是可行的,但实际上并没有。我发现通过分叉 child 然后执行 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
我是 运行 一个 etcd
进程,在您终止它之前它一直处于活动状态。 (它不提供守护进程模式选项。)我想分离它以便我可以保留 运行 更多 python.
我会在 shell;
做什么etcd & next_cmd
我正在使用 python 的 sh
库,受到整个互联网的热烈推荐。我不想深入研究 subprocess
或 Popen
,但我也没有找到使用它们的解决方案。
我想要的;
sh.etcd(detach=True)
sh.next_cmd()
或
sh.etcd("&")
sh.next_cmd()
不幸的是 detach
不是 kwarg 并且 sh
将 "&"
视为 etcd
的标志。
我在这里遗漏了什么吗?这样做的好方法是什么?
请注意,在以下两个示例中调用了
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)
这使用传统的 fork
和 exec
模型,其工作方式与
在 Python 中很好,就像在 C 中一样。在这个模型中,etcd
的输出
将显示在您的控制台上,这可能是您想要的,也可能不是您想要的。您可以通过在子进程中重定向 stdout
和 stderr
来控制它。
要实现 sh
的 &
,避免 cargo cult 编程并直接使用 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()
这会忽略异常处理和您关于 "daemon mode" 的讨论(如果您想在 Python 中实现守护进程;请使用 python-daemon. To run a process as a system service, use whatever your OS provides or a supervisor program such as supervisord
)。
这里是 sh 的作者。我相信你想使用 _bg
特殊关键字参数 http://amoffat.github.io/sh/#background-processes
这将立即分叉您的命令和 return。即使在您的脚本退出后,该过程仍将继续 运行。
如果下次我 google 同样的问题时发现它,没有其他原因就发布这个:
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 以外的文件描述符,因此代码明确关闭它们。
子流程也很容易做到这一点:
这种方法有效 (python3)。关键是使用“start_new_session=True”
更新:尽管 Popen 文档说这是可行的,但实际上并没有。我发现通过分叉 child 然后执行 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