当前位置: 首页 > 面试题库 >

Python子进程Popen.communicate()是否等效于Popen.stdout.read()?

尤飞尘
2023-03-14
问题内容

非常具体的问题(我希望如此): 以下三个代码之间有什么区别?

(我希望只是第一个不会等待子进程完成,而第二个和第三个会完成。但是我需要确保这是 唯一的 区别…)

我也欢迎其他评论/建议(尽管我已经很清楚shell=True危险和跨平台限制)

请注意,我已经阅读了Python子进程交互,为什么我的进程可以使用Popen.communicate而不使用Popen.stdout.read()?并且我不想/不需要之后与该程序进行交互。

最后,请注意,我知道在某处使用一种方法将一个缓冲区填充为一个输出时会有死锁的风险,但是我在互联网上寻找清晰的解释时迷路了…

第一个代码:

from subprocess import Popen, PIPE

def exe_f(command='ls -l', shell=True):
    """Function to execute a command and return stuff"""

    process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)

    stdout = process.stdout.read()
    stderr = process.stderr.read()

    return process, stderr, stdout

第二个代码:

from subprocess import Popen, PIPE
from subprocess import communicate

def exe_f(command='ls -l', shell=True):
    """Function to execute a command and return stuff"""

    process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)

    (stdout, stderr) = process.communicate()

    return process, stderr, stdout

第三码:

from subprocess import Popen, PIPE
from subprocess import wait

def exe_f(command='ls -l', shell=True):
    """Function to execute a command and return stuff"""

    process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)

    code   = process.wait()
    stdout = process.stdout.read()
    stderr = process.stderr.read()

    return process, stderr, stdout

谢谢。


问题答案:

如果您查看的来源subprocess.communicate(),则显示了差异的完美示例:

def communicate(self, input=None):
    ...
    # Optimization: If we are only using one pipe, or no pipe at
    # all, using select() or threads is unnecessary.
    if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
        stdout = None
        stderr = None
        if self.stdin:
            if input:
                self.stdin.write(input)
            self.stdin.close()
        elif self.stdout:
            stdout = self.stdout.read()
            self.stdout.close()
        elif self.stderr:
            stderr = self.stderr.read()
            self.stderr.close()
        self.wait()
        return (stdout, stderr)

    return self._communicate(input)

你可以看到,communicate确实让使用读取调用来stdoutstderr,还呼吁wait()。这只是操作顺序的问题。在您的情况下,因为您同时使用PIPE了stdout和stderr,它进入_communicate()

def _communicate(self, input):
    stdout = None # Return
    stderr = None # Return

    if self.stdout:
        stdout = []
        stdout_thread = threading.Thread(target=self._readerthread,
                                         args=(self.stdout, stdout))
        stdout_thread.setDaemon(True)
        stdout_thread.start()
    if self.stderr:
        stderr = []
        stderr_thread = threading.Thread(target=self._readerthread,
                                         args=(self.stderr, stderr))
        stderr_thread.setDaemon(True)
        stderr_thread.start()

    if self.stdin:
        if input is not None:
            self.stdin.write(input)
        self.stdin.close()

    if self.stdout:
        stdout_thread.join()
    if self.stderr:
        stderr_thread.join()

    # All data exchanged.  Translate html" target="_blank">lists into strings.
    if stdout is not None:
        stdout = stdout[0]
    if stderr is not None:
        stderr = stderr[0]

    # Translate newlines, if requested.  We cannot let the file
    # object do the translation: It is based on stdio, which is
    # impossible to combine with select (unless forcing no
    # buffering).
    if self.universal_newlines and hasattr(file, 'newlines'):
        if stdout:
            stdout = self._translate_newlines(stdout)
        if stderr:
            stderr = self._translate_newlines(stderr)

    self.wait()
    return (stdout, stderr)

这使用线程一次读取多个流。然后wait()在最后调用。

总结一下:

  1. 本示例一次从一个流中读取,并且不等待它完成该过程。
  2. 本示例通过内部线程同时从两个流中读取,并等待它完成该过程。
  3. 本示例等待过程完成,然后一次读取一个流。正如您提到的,如果流中写入的内容过多,则有可能导致死锁。

另外,在第二个和第三个示例中,您不需要这两个import语句:

from subprocess import communicate
from subprocess import wait

它们都是Popen对象的方法。



 类似资料:
  • 问题内容: 最近,我遇到了一些Java代码,这些代码简单地将一些字符串放入Java TreeSet中,为其实现了基于距离的比较器,然后在日落时分快乐地计算出给定的分数来解决给定的问题。 我的问题 是否有适用于Python的等效数据结构? Java树集看起来基本上是一个有序字典,可以使用某种比较器来实现这种排序。 我看到有一个用于 OrderedDict的Py3K的PEP,但是我使用的是2.6.x。

  • 问题内容: 我想从某些shell命令(例如或python脚本)中获取输出。我看到已弃用,但只会得到返回代码。 我希望有一些简单的解决方案。 问题答案: 使用 subprocess.Popen : 请注意,通信将阻塞,直到该过程终止。如果在终止之前需要输出,则可以使用 process.stdout.readline() 。有关更多信息,请参见文档。

  • 本文向大家介绍MySQL LIMIT子句是否等效于SQL SERVER?,包括了MySQL LIMIT子句是否等效于SQL SERVER?的使用技巧和注意事项,需要的朋友参考一下 首先,我们需要创建一个表来了解limit子句(对于SQL Server来说是我们想要的)。我们将在CREATE命令的帮助下创建一个表。 建立表格 之后,让我们将记录插入表中- 在SELECT语句的帮助下显示所有记录- 以

  • 问题内容: 我正在配置Java客户端,它的工作是建立与服务器的TLS连接。我想使用以下3种密码配置客户端: 在Java支持的密码套件中,我找到了相同的密码,但是开头是SSL,而不是TLS。问题是,如果我用以下方法配置了客户端: 这两个列表是否完全相同,并且服务器将对其进行解释?我担心是否为客户端配置了密码,这意味着与某些不同,并且可能某些服务器不支持。我如何确定? 问题答案: 是的,它们是相同的。

  • 问题内容: Java是否具有等效于Python 方法的方法? 问题答案: Guava还提供类似于Python的东西: 您也可以使用Guava的AbstractIterator实现一个相当简单的迭代器来执行相同的操作:

  • 问题内容: 我在SceneDelegate中定义了一个let属性。我希望某些ViewController能够在场景中访问它。 在UIKit中,我可以这样访问App Delegate属性: 然后强制转换并指定属性名称… 是否有等效的方法可以从UIViewController的实例获取对视图控制器所在的SceneDelegate的引用? 问题答案: 从iOS 13开始,具有的属性。这些场景中的每一个都

  • 问题内容: 我的要求是拥有一个线程,该线程可以维护BlackBerry设备与服务器之间的套接字连接并交换命令,类似于请求和响应。 我的问题是,我需要这个线程在后台运行 所有的时间 ,并保持提供给用户的UI。因此,当服务器发出命令时,此线程将对其进行解析并更新UI,并且如果BlackBerry用户发出了操作,则该线程会将其发送到服务器,然后服务器将对其进行处理。 我在Android中使用开发了相同的

  • 问题内容: 在Python中,该函数允许您迭代一系列(索引,值)对。例如: 用Java有什么办法吗? 问题答案: 对于实现接口的集合,您可以调用方法以获取。迭代器(还有其他方法)有两种方法- ,以获得索引;和,以获取值(与其他迭代器一样)。 因此,上述Python的Java等效项可能是: 与Python一样,它输出: