重用和关闭子流程对象的正确方法 [英] Proper way of re-using and closing a subprocess object

查看:35
本文介绍了重用和关闭子流程对象的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在循环中有以下代码:

虽然为真:# 定义 shell_commandp1 = Popen(shell_command, shell=shell_type, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid)结果 = p1.stdout.read();# 定义条件如果条件:休息;

其中 shell_command 类似于 ls(它只是打印内容).

我在不同的地方读到过,我可以通过多种方式关闭/终止/退出 Popen 对象,例如:

p1.stdout.close()p1.stdin.close()p1. 终止p1.kill

我的问题是:

  1. 在使用完 subprocess 对象后,关闭它的正确方法是什么?
  2. 考虑到我的脚本的性质,有没有办法只打开一个 subprocess 对象并用不同的 shell 命令重用它?这会比每次打开新的 subprocess 对象更有效吗?

更新

根据我是使用 p1.communicate() 还是 p1.stdout.read() 进行交互,我仍然对要遵循的步骤顺序感到困惑与我的过程.

根据我在答案和评论中的理解:

如果我使用 p1.communicate() 我不必担心释放资源,因为 communicate() 会等到进程完成,抓住输出并正确关闭 subprocess 对象

如果我遵循 p1.stdout.read() 路线(我认为这适合我的情况,因为 shell 命令只是应该打印内容)我应该按以下顺序调用:

  1. p1.wait()
  2. p1.stdout.read()
  3. p1.terminate()

是吗?

解决方案

一旦我们使用完一个子流程对象,关闭它的正确方法是什么?

stdout.close()stdin.close() 不会终止进程除非它在输入结束或写入错误.

.terminate().kill()两者都可以完成工作,kill 在 POSIX 系统上更加激烈",因为 SIGKILL 被发送,应用程序不能忽略它.例如,本博文解释了具体差异.在 Windows 上,没有区别.

另外,记得.wait() 并在杀死进程后关闭管道以避免僵尸并强制释放资源.

经常遇到的一个特殊情况是从 STDIN 读取并将结果写入 STDOUT 的进程,当遇到 EOF 时关闭自己.对于这些类型的程序,使用 subprocess.communicate 通常是明智的:

<预><代码>>>>p = Popen(["sort"], stdin=PIPE, stdout=PIPE)>>>p.communicate("4\n3\n1")('1\n3\n4\n', 无)>>>p.返回码0

这也可用于打印某些内容并在之后立即退出的程序:

<预><代码>>>>p = Popen(["ls", "/home/niklas/test"], stdin=PIPE, stdout=PIPE)>>>p.communicate()('file1\nfile2\n', 无)>>>p.返回码0

<块引用>

考虑到我的脚本的性质,有没有办法只打开一个子进程对象并用不同的 shell 命令重用它?这会比每次打开新的子流程对象更有效吗?

我认为 subprocess 模块不支持这一点,而且我看不到可以在此处共享哪些资源,因此我认为这不会给您带来显着优势.

I have the following code in a loop:

while true:
    # Define shell_command
    p1 = Popen(shell_command, shell=shell_type, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid)
    result = p1.stdout.read(); 
    # Define condition
    if condition:
       break;

where shell_command is something like ls (it just prints stuff).

I have read in different places that I can close/terminate/exit a Popen object in a variety of ways, e.g. :

p1.stdout.close()
p1.stdin.close()
p1.terminate
p1.kill

My question is:

  1. What is the proper way of closing a subprocess object once we are done using it?
  2. Considering the nature of my script, is there a way to open a subprocess object only once and reuse it with different shell commands? Would that be more efficient in any way than opening new subprocess objects each time?

Update

I am still a bit confused about the sequence of steps to follow depending on whether I use p1.communicate() or p1.stdout.read() to interact with my process.

From what I understood in the answers and the comments:

If I use p1.communicate() I don't have to worry about releasing resources, since communicate() would wait until the process is finished, grab the output and properly close the subprocess object

If I follow the p1.stdout.read() route (which I think fits my situation, since the shell command is just supposed to print stuff) I should call things in this order:

  1. p1.wait()
  2. p1.stdout.read()
  3. p1.terminate()

Is that right?

解决方案

What is the proper way of closing a subprocess object once we are done using it?

stdout.close() and stdin.close() will not terminate a process unless it exits itself on end of input or on write errors.

.terminate() and .kill() both do the job, with kill being a bit more "drastic" on POSIX systems, as SIGKILL is sent, which cannot be ignored by the application. Specific differences are explained in this blog post, for example. On Windows, there's no difference.

Also, remember to .wait() and to close the pipes after killing a process to avoid zombies and force the freeing of resources.

A special case that is often encountered are processes which read from STDIN and write their result to STDOUT, closing themselves when EOF is encountered. With these kinds of programs, it's often sensible to use subprocess.communicate:

>>> p = Popen(["sort"], stdin=PIPE, stdout=PIPE)
>>> p.communicate("4\n3\n1")
('1\n3\n4\n', None)
>>> p.returncode
0

This can also be used for programs which print something and exit right after:

>>> p = Popen(["ls", "/home/niklas/test"], stdin=PIPE, stdout=PIPE)
>>> p.communicate()
('file1\nfile2\n', None)
>>> p.returncode
0

Considering the nature of my script, is there a way to open a subprocess object only once and reuse it with different shell commands? Would that be more efficient in any way than opening new subprocess objects each time?

I don't think the subprocess module supports this and I don't see what resources could be shared here, so I don't think it would give you a significant advantage.

这篇关于重用和关闭子流程对象的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆