首页 > 代码库 > Python线程通信

Python线程通信

subprocess

作用

模块用于生产新的进程,连接到其输入、输出、错误管道,并获取其返回值

1. 如何使用subprocess模块

启动子进程的推荐方法是使用以下方便功能。 对于更高级的用例,当这些不满足您的需要时,使用底层的Popen interface

  • subprocess.call(args*stdin=Nonestdout=Nonestderr=Noneshell=False)

作用:调用如args所示的系统命令,等待命令完成,返回returncode

Example:

>>> subprocess.call(["ls", "-l"])
0

>>> subprocess.call("exit 1", shell=True)
1

警告:使用shell = True可能是一个安全隐患。

注意:不要使用stdout = PIPE或stderr = PIPE,因为它可能发生子进程输出的死锁。 当需要管道时,使用popen与communicate()方法

  • subprocess.check_call(args*stdin=Nonestdout=Nonestderr=Noneshell=False)

运行带参数的命令。 等待命令完成。 如果返回码为零,那么返回,否则抛出CalledProcessError。 CalledProcessError对象将在returncode属性中具有返回码

Example:

>>> subprocess.check_call(["ls", "-l"])
0

>>> subprocess.check_call("exit 1", shell=True)
Traceback (most recent call last):
   ...
subprocess.CalledProcessError: Command ‘exit 1‘ returned non-zero exit status 1
  • subprocess.check_output(args*stdin=Nonestderr=Noneshell=Falseuniversal_newlines=False)

运行系统命令,并将输出返回给一个字节字符串,如果返回值不为0,则抛出CalledProcessError异常。

Example:

>>> subprocess.check_output(["echo", "Hello World!"])
‘Hello World!\n‘

>>> subprocess.check_output("exit 1", shell=True)
Traceback (most recent call last):
   ...
subprocess.CalledProcessError: Command ‘exit 1‘ returned non-zero exit status 1

  想要捕获错误信息,使用stderr=subprocess.STDOUT:

>>> subprocess.check_output(
...     "ls non_existent_file; exit 0",
...     stderr=subprocess.STDOUT,
...     shell=True)
‘ls: non_existent_file: No such file or directory\n‘
  • subprocess.PIPE

特殊值,可以用作popen的stdin,stdout或stderr参数,并指示应打开标准流的管道。

  • subprocess.STDOUT

可以用作Popen的stderr参数的特殊值,表示标准错误应该作为标准输出进入相同的句柄。

  • 为了支持各种各样的用例,Popen构造函数(和方便函数)接受大量的可选参数。对于大多数典型的用例,许多这些参数可以安全地保留其默认值。最常需要的参数是:

    args是所有调用所必需的,应该是一个字符串或一系列程序参数。提供参数序列通常是优选的,因为它允许模块处理任何所需的转义和引用参数(例如,以允许文件名中的空格)。如果传递单个字符串,则shell必须为True(见下文),否则字符串必须简单地命名要执行的程序,而不指定任何参数。

    stdin,stdout和stderr分别指定执行程序的标准输入,标准输出和标准错误文件句柄。有效值为PIPE,现有文件描述符(正整数),现有文件对象和无。 PIPE表示应该创建一个新的管道给孩子。使用默认设置None,不会发生重定向;子进程的文件句柄将从父进程继承。此外,stderr可以是STDOUT,它指示来自子进程的stderr数据应该捕获到与stdout相同的文件句柄中。

    当stdout或stderr是管道,universal_newlines为True时,所有行尾都将转换为‘\ n‘,如open()的通用换行符‘U‘模式参数所述。

    如果shell为True,指定的命令将通过shell执行。如果你使用Python主要用于增强的控制流,它提供了大多数系统shell,并仍然想要方便地访问其他shell功能,如shell管道,文件名通配符,环境变量扩展和扩展?到用户的家

使用了shell=True这个参数。这个时候,我们使用一整个字符串,而不是一个表来运行子进程。Python将先运行一个shell,再用这个shell来解释这整个字符串。

Example:

import subprocess
out = subprocess.call("ls -l", shell=True)
out = subprocess.call("cd ..", shell=True)
  • Popen 构造器
  • 此模块中的基础过程创建和管理由Popen类处理。它提供了很多灵活性,以便开发人员能够处理方便功能未涵盖的较不常见的情况。

    class subprocess.Popen(args,bufsize = 0,executable = None,stdin = None,stdout = None,stderr = None,preexec_fn = None,close_fds = False,shell = False,cwd = None,env = None,universal_newlines = False ,startupinfo = None,creationflags = 0)
    在新进程中执行子程序。在Unix上,类使用os.execvp() - 类行为来执行子程序。在Windows上,类使用Windows CreateProcess()函数。 Popen的参数如下。

    args应该是一个程序参数序列或者一个单个字符串。默认情况下,如果args是一个序列,则要执行的程序是args中的第一个项目。如果args是字符串,解释是平台相关的,如下所述。有关与默认行为的其他差异,请参阅shell和可执行参数。除非另有说明,建议将args作为序列传递。

  • Example:
  • >>> import shlex, subprocess
    >>> command_line = raw_input()
    /bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo ‘$MONEY‘"
    >>> args = shlex.split(command_line)
    >>> print args
    [‘/bin/vikings‘, ‘-input‘, ‘eggs.txt‘, ‘-output‘, ‘spam spam.txt‘, ‘-cmd‘, "echo ‘$MONEY‘"]
    >>> p = subprocess.Popen(args) # Success!
    
  • shell参数(默认为False)指定是否使用shell作为程序执行。 如果shell为True,则建议将args作为字符串而不是序列传递。

    在Unix上,shell = True,shell默认为/ bin / sh。 如果args是字符串,则该字符串指定要通过shell执行的命令。 这意味着字符串的格式必须与在shell提示符下键入时的格式完全一致。 这包括,例如,引用或反斜杠转义文件名中带有空格。 如果args是序列,则第一个项指定命令字符串,任何其他项将被视为shell本身的附加参数。 也就是说,Popen相当于:

  • Popen([‘/bin/sh‘, ‘-c‘, args[0], args[1], ...])
  • 在shell = true的Windows上,COMSPEC环境变量指定默认shell。 只有当你需要在Windows上指定shell = True的时候,你希望执行的命令是内置在shell中(例如dir或copy)。 您不需要shell = True来运行批处理文件或基于控制台的可执行文件。
  • bufsize(如果给定)与内置open()函数的相应参数意义相同:0表示无缓冲,1表示行缓冲,任何其他正值表示使用大小为(大约)的缓冲区。 负bufsize意味着使用系统默认值,这通常意味着完全缓冲。 bufsize的默认值为0(未缓冲)。
  • 如果遇到性能问题,尝试通过将bufsize设置为-1或足够大的正值(例如4096)来启用缓冲。
  • 如果preexec_fn设置为可调用对象,则该对象将在子进程中在子进程执行之前被调用。 (仅限Unix)

    如果close_fds为true,除了0,1和2之外的所有文件描述符将在子进程执行之前关闭。 (仅限Unix)。 或者,在Windows上,如果close_fds为true,则子进程将不继承任何句柄。 请注意,在Windows上,您不能将close_fds设置为true,也可以通过设置stdin,stdout或stderr重定向标准句柄。

    如果cwd不是None,子进程的当前目录在执行之前将被更改为cwd。 注意,在搜索可执行文件时不考虑此目录,因此您不能指定程序相对于cwd的路径。

    如果env不是None,它必须是定义新进程的环境变量的映射; 这些是使用而不是继承当前进程的环境,这是默认行为。

  • 注意如果指定,env必须提供程序执行所需的任何变量。 在Windows上,为了运行side-by-side程序集,指定的env必须包含一个有效的SystemRoot。
    如果universal_newlines为True,文件对象stdout和stderr在通用换行模式下作为文本文件打开。 行可以由‘\ n‘,Unix行尾约定,‘\ r‘,旧的Macintosh约定或‘\ r \ n‘(Windows约定)中的任何一个终止。 所有这些外部表示被Python程序看作‘\ n‘。

  • Exception
    • 如果在新程序开始执行之前,在子进程中引发的异常,将在父进程中重新生成。 此外,异常对象将有一个额外的属性称为child_traceback,这是一个字符串,包含从孩子的角度的追溯信息。

      最常见的异常是OSError。 例如,当尝试执行不存在的文件时,会发生这种情况。 应用程序应准备OSError异常。

      如果使用无效参数调用Popen,将引发ValueError。

      如果被调用的进程返回非零返回码,check_call()和check_output()将引发CalledProcessError。

  • Security
    • 与其他popen函数不同,这个实现不会隐式地调用系统shell。 这意味着所有字符,包括shell元字符,都可以安全地传递给子进程。 显然,如果shell被显式地调用,则应用程序有责任确保所有空格和元字符被适当地引用。

Popen对象

  • import subprocess
    child = subprocess.Popen(["ping","-c","5","www.google.com"])
    child.wait()
    print("parent process")

     

    此外,你还可以在父进程中对子进程进行其它操作,比如我们上面例子中的child对象:

    child.poll()           # 检查子进程状态

    child.kill()           # 终止子进程

    child.send_signal()    # 向子进程发送信号

    child.terminate()      # 终止子进程

 

Popen.poll()

Popen.wait()

  • Popen.communicate(input = None)

与进程交互:将数据发送到stdin。 从stdout和stderr读取数据,直到达到文件结束。 等待进程终止。 可选输入参数应为要发送到子进程的字符串,如果没有数据应发送到子进程,则为None。

communicate()返回一个元组(stdoutdata,stderrdata)。

注意,如果你想发送数据到进程的stdin,你需要使用stdin = PIPE来创建Popen对象。 类似地,要在结果元组中获取除了None之外的任何值,您需要同时给予stdout = PIPE和/或stderr = PIPE。

Popen.stdin
如果stdin参数是PIPE,则此属性是向子进程提供输入的文件对象。 否则,它为无。

Popen.stdout
如果stdout参数是PIPE,则此属性是提供子进程输出的文件对象。 否则,它为无。

Popen.stderr
如果stderr参数是PIPE,则此属性是一个文件对象,它提供子进程的错误输出。 否则,它为无。

Popen.pid
子进程的进程ID。

请注意,如果将shell参数设置为True,那么这是生成的shell的进程ID。

Popen.returncode
子返回码,由poll()和wait()设置(间接通过communic())。 无值表示进程尚未终止。

负值-N表示子节点由信号N(仅限Unix)终止。

Python线程通信