在Python中运行后台进程,不要等待

时间:2016-05-05 18:44:58

标签: python subprocess background-process popen

我的目标很简单:启动rsync并且不要等待。

Debian上的Python 2.7.9

示例代码:

rsync_cmd = "/usr/bin/rsync -a -e 'ssh -i /home/myuser/.ssh/id_rsa' {0}@{1}:'{2}' {3}".format(remote_user, remote_server, file1, file1)
rsync_cmd2 = "/usr/bin/rsync -a -e 'ssh -i /home/myuser/.ssh/id_rsa' {0}@{1}:'{2}' {3} &".format(remote_user, remote_server, file1, file1)
rsync_path = "/usr/bin/rsync"
rsync_args = shlex.split("-a -e 'ssh -i /home/mysuser/.ssh/id_rsa' {0}@{1}:'{2}' {3}".format(remote_user, remote_server, file1, file1))
#subprocess.call(rsync_cmd, shell=True)     # This isn't supposed to work but I tried it
#subprocess.Popen(rsync_cmd, shell=True)    # This is supposed to be the solution but not for me
#subprocess.Popen(rsync_cmd2, shell=True)   # Adding my own shell "&" to background it, still fails
#subprocess.Popen(rsync_cmd, shell=True, stdin=None, stdout=None, stderr=None, close_fds=True)  # This doesn't work
#subprocess.Popen(shlex.split(rsync_cmd))   # This doesn't work
#os.execv(rsync_path, rsync_args)           # This doesn't work
#os.spawnv(os.P_NOWAIT, rsync_path, rsync_args) # This doesn't work
#os.system(rsync_cmd2)                      # This doesn't work
print "DONE"

(我已经注释掉执行命令只是因为我实际上将所有试验保存在我的代码中,以便我知道我做了什么以及我做了什么。显然,我会运行脚本右边的行没有注释。)

这会发生什么......我可以在服务器上观看传输,一旦完成,我就会在屏幕上显示“完成”。

我希望发生的是在发出rsync命令后立即打印“DONE”并开始传输。

似乎非常直截了当。我已经按照其他帖子中列出的详细信息,例如this一个和this一个,但有些事情阻止了它为我工作。

提前致谢。

(我已经尝试了我在StackExchange中可以找到的所有东西,并且不觉得这是重复的,因为我仍然无法让它工作。在我的设置中有些东西不对,需要帮助。)

3 个答案:

答案 0 :(得分:14)

以下是Python REPL的验证示例:

>>> import subprocess
>>> import sys
>>> p = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(100)'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT); print('finished')
finished

如何通过另一个终端窗口验证:

$ ps aux | grep python

输出:

user           32820   0.0  0.0  2447684   3972 s003  S+   10:11PM   0:00.01 /Users/user/venv/bin/python -c import time; time.sleep(100)

答案 1 :(得分:7)

Popen()启动子进程 - 它不会等待它退出。如果要等待子进程,则必须显式调用.wait()方法。从这个意义上讲,所有子进程都是后台进程。

另一方面,子进程可以从父进程继承各种属性/资源,例如打开文件描述符,进程组,其控制终端,一些信号配置等 - 它可能导致阻止祖先进程退出,例如,Python subprocess .check_call vs .check_output或孩子可能会在Ctrl-C上过早死亡(SIGINT信号被发送到前台进程组)或者终端会话被关闭(SIGHUP)。

要完全取消与子进程的关联,您应该将其设为daemon。有时候介于两者之间的东西就足够了,例如redirect the inherited stdout in a grandchild so that .communicate() in the parent would return when its immediate child exits就足够了。

答案 2 :(得分:1)

我在使用qnx设备时遇到了类似的问题,并且希望有一个独立于主进程甚至在主进程终止后运行的子进程。 这是我发现可以实际使用的解决方案' creationflags = subprocess.DETACHED_PROCESS ':

import subprocess
import time

pid = subprocess.Popen(["python", "path_to_script\turn_ecu_on.py"], creationflags=subprocess.DETACHED_PROCESS)

time.sleep(15)
print("Done")

链接到文档:https://docs.python.org/3/library/subprocess.html#subprocess.Popen