subprocess模块允许你生成新的进程,连接它们的输入、输出、错误管道,并且获取它们的返回码。此模块打算代替一些老旧的模块与功能:
os.system os.spawn*
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None, **other_popen_kwargs)
- >>>subprocess.run(["ls", "-l"]) # doesn't capture output
- CompletedProcess(args=['ls', '-l'], returncode=0)
-
- >>>subprocess.run("exit 1", shell=True, check=True)
- Traceback (most recent call last):
- ...
- subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
-
- >>>subprocess.run(["ls", "-l", "/dev/null"], capture_output=True)
- CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
- stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n', stderr=b'')
class subprocess.CompletedProcess
run() 的返回值, 代表一个进程已经结束.
主要的属性和方法:
属性和方法名 | 说明 |
args | 被用作启动进程的参数. 可能是一个列表或字符串. |
returncode | 子进程的退出状态码. 通常来说, 一个为 0 的退出码表示进程运行正常. 一个负值 |
stdout | 从子进程捕获到的标准输出. 一个字节序列, 或一个字符串, 如果 run() 是设置了 encoding, errors 或者 text=True 来运行的. 如果未有捕获, 则为 None. 如果你通过 stderr=subprocess.STDOUT 运行进程,标准输入和标准错误将被组合在这个属性中,并且 stderr 将为 None。 |
stderr | 捕获到的子进程的标准错误. 一个字节序列, 或者一个字符串, 如果 run() 是设置了参数 encoding, errors 或者 text=True 运行的. 如果未有捕获, 则为 None. |
check_returncode() | 如果 returncode 非零, 抛出 CalledProcessError. |
class subprocess.Popen(args, bufsize=- 1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=None, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, group=None, extra_groups=None, user=None, umask=- 1, encoding=None, errors=None, text=None, pipesize=- 1, process_group=None)
向外部函数传入序列形式参数的一个例子如下:
Popen(["/usr/bin/git", "commit", "-m", "Fixes a bug."])
在 POSIX,如果 args 是一个字符串,此字符串被作为将被执行的程序的命名或路径解释。但是,只有在不传递任何参数给程序的情况下才能这么做。
shell=True
, shell 默认为 /bin/sh
。如果 args 是一个字符串,此字符串指定将通过 shell 执行的命令。这意味着字符串的格式必须和在命令提示符中所输入的完全相同。这包括,例如,引号和反斜杠转义包含空格的文件名。如果 args 是一个序列,第一项指定了命令,另外的项目将作为传递给 shell (而非命令) 的参数对待。也就是说, Popen 等同于:Popen(['/bin/sh', '-c', args[0], args[1], ...])
在 3.3.1 版更改: bufsize 现在默认为 -1 表示启用缓冲以符合大多数代码所期望的行为。 在 Python 3.2.4 和 3.3.1 之前的版本中它错误地将默认值设为 0
即无缓冲并且允许短读取。 这是无意的失误并且与大多数代码所期望的 Python 2 的行为不一致。
shell=True
, executable 替换 args 指定运行的程序。但是,原始的 args 仍然被传递给程序。大多数程序将被 args 指定的程序作为命令名对待,这可以与实际运行的程序不同。在 POSIX, args 名作为实际调用程序中可执行文件的显示名称,例如 ps。如果 shell=True
,在 POSIX, executable 参数指定用于替换默认 shell /bin/sh
的 shell。setsid()
系统调用将在执行子进程之前在子进程中执行。setpgid(0, value)
系统调用将在执行子进程之前在子进程中执行。Popen 对象支持通过 with 语句作为上下文管理器,在退出时关闭文件描述符并等待进程:
with Popen(["ifconfig"], stdout=PIPE) as proc: log.write(proc.stdout.read())
Popen()的返回对象,主要方法和属性:
属性和方法名 | 说明 |
Popen.poll() | 检查子进程是否已被终止。设置并返回 returncode 属性。否则返回 None。 |
Popen.wait(timeout=None) | 等待子进程被终止。设置并返回 returncode 属性。如果进程在 timeout 秒后未中断,抛出一个 TimeoutExpired 异常,可以安全地捕获此异常并重新等待。 |
Popen.communicate(input=None, timeout=None) | 与进程交互:将数据发送到 stdin。 从 stdout 和 stderr 读取数据,直到抵达文件结尾。 等待进程终止并设置 returncode 属性。 可选的 input 参数应为要发送到下级进程的数据,或者如果没有要发送到下级进程的数据则为 None。 如果流是以文本模式打开的,则 input 必须为字符串。 在其他情况下,它必须为字节串。 communicate() 返回一个 (stdout_data, stderr_data) 元组。如果文件以文本模式打开则为字符串;否则字节。 注意如果你想要向进程的 stdin 传输数据,你需要通过 stdin=PIPE 创建此 Popen 对象。类似的,要从结果元组获取任何非 None 值,你同样需要设置 stdout=PIPE 或者 stderr=PIPE。 如果进程在 timeout 秒后未终止,一个 TimeoutExpired 异常将被抛出。捕获此异常并重新等待将不会丢失任何输出。 如果超时到期,子进程不会被杀死,所以为了正确清理一个行为良好的应用程序应该杀死子进程并完成通讯。 |
Popen.send_signal(signal) | 将信号 signal 发送给子进程。如果进程已完成则不做任何操作 |
Popen.terminate() | 停止子进程。 在 POSIX 操作系统上,此方法会发送 SIGTERM 给子进程。 在 Windows 上则会调用 Win32 API 函数 TerminateProcess() 来停止子进程。 |
Popen.kill() | 杀死子进程。 在 POSIX 操作系统上,此函数会发送 SIGKILL 给子进程。 在 Windows 上 kill() 则是 terminate() 的别名。 |
Popen.args | 传递给 Popen 的参数 |
Popen.stdin | 如果 stdin 参数为 PIPE,此属性是一个类似 open() 所返回对象的可写流对象。 如果指定了 encoding 或 errors 参数或者 text 或 universal_newlines 参数为 True,则这个流将是一个文本流,否则将是一个字节流。 如果 stdin 参数不为 PIPE,则此属性将为 None。 |
Popen.stdout | 如果 stdout 参数为 PIPE,此属性是一个类似 open() 所返回对象的可读流对象。 从流中读取将会提供来自子进程的输出。 如果 encoding 或 errors 参数被指定或者 text 或 universal_newlines 参数为 True,则这个流将是一个文本流,否则将是一个字节流。 如果 stdout 参数不为 PIPE,则此属性将为 None。 |
Popen.stderr | 如果 stderr 参数为 PIPE,此属性是一个类似 open() 所返回对象的可读流对象。 从流中读取将会提供来自子进程的错误输出。 如果 encoding 或 errors 参数被指定或者 text 或 universal_newlines 参数为 True,则这个流将是一个文本流,否则将是一个字节流。 如果 stderr 参数不为 PIPE,则此属性将为 None。 |
Popen.pid | 子进程的进程号。注意如果你设置了 shell 参数为 True ,则这是生成的子 shell 的进程号。 |
Popen.returncode | 子进程的返回码。 初始为 None,returncode 是通过在检测到进程终结时调用 poll(), wait() 或 communicate() 等方法来设置的。 None 值表示在最近一次方法调用时进程尚未终结 一个负值 -N 表示子进程被信号 N 中断 (仅 POSIX). |
concurrent.futures 模块提供异步执行可调用对象高层接口。
异步执行可以由 ThreadPoolExecutor 使用线程或由 ProcessPoolExecutor 使用单独的进程来实现。 两者都是实现抽象类 Executor 定义的接口。
class concurrent.futures.Executor
抽象类提供异步执行调用方法。要通过它的子类调用,而不是直接调用。
submit(fn, /, *args, **kwargs)
调度可调用对象 fn,以 fn(*args, **kwargs) 方式执行并返回一个代表该可调用对象的执行的 Future 对象。
- with ThreadPoolExecutor(max_workers=1) as executor:
- future = executor.submit(pow, 323, 1235)
- print(future.result())
map(func, *iterables, timeout=None, chunksize=1)
类似于 map(func, *iterables) 函数,除了以下两点:
如果 __next__() 被调用且从对 Executor.map() 原始调用 timeout 秒之后其结果还不可用则已返回的迭代器将引发 TimeoutError。 timeout 可以是整数或浮点数。 如果 timeout 未指定或为 None,则不限制等待时间。
如果 func 调用引发一个异常,当从迭代器中取回它的值时这个异常将被引发。
使用 ProcessPoolExecutor 时,这个方法会将 iterables 分割任务块并作为独立的任务并提交到执行池中。这些块的大概数量可以由 chunksize 指定正整数设置。 对很长的迭代器来说,使用大的 chunksize 值比默认值 1 能显著地提高性能。 chunksize 对 ThreadPoolExecutor 没有效果。
在 3.5 版更改: 加入 chunksize 参数。
shutdown(wait=True, *, cancel_futures=False)
当待执行的 future 对象完成执行后向执行者发送信号,它就会释放正在使用的任何资源。 在关闭后调用 Executor.submit() 和 Executor.map() 将会引发 RuntimeError。
如果 wait 为 True 则此方法只有在所有待执行的 future 对象完成执行且释放已分配的资源后才会返回。 如果 wait 为 False,方法立即返回,所有待执行的 future 对象完成执行后会释放已分配的资源。 不管 wait 的值是什么,整个 Python 程序将等到所有待执行的 future 对象完成执行后才退出。
如果 cancel_futures 为 True,此方法将取消所有执行器还未开始运行的挂起的 Future。无论 cancel_futures 的值是什么,任何已完成或正在运行的 Future 都不会被取消。
如果 cancel_futures 和 wait 均为 True,则执行器已开始运行的所有 Future 将在此方法返回之前完成。 其余的 Future 会被取消。
如果使用 with 语句,你就可以避免显式调用这个方法,它将会停止 Executor (就好像 Executor.shutdown() 调用时 wait 设为 True 一样等待):
- import shutil
- with ThreadPoolExecutor(max_workers=4) as e:
- e.submit(shutil.copy, 'src1.txt', 'dest1.txt')
- e.submit(shutil.copy, 'src2.txt', 'dest2.txt')
- e.submit(shutil.copy, 'src3.txt', 'dest3.txt')
- e.submit(shutil.copy, 'src4.txt', 'dest4.txt')
在 3.9 版更改: 增加了 cancel_futures。
ProcessPoolExecutor 类是 Executor 的子类,它使用进程池来异步地执行调用。 ProcessPoolExecutor 会使用 multiprocessing 模块,这允许它绕过 全局解释器锁 但也意味着只可以处理和返回可封存的对象。
__main__ 模块必须可以被工作者子进程导入。这意味着 ProcessPoolExecutor 不可以工作在交互式解释器中。
从可调用对象中调用 Executor 或 Future 的方法提交给 ProcessPoolExecutor 会导致死锁。
class concurrent.futures.ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=(), max_tasks_per_child=None)
- import concurrent.futures
- import math
-
- PRIMES = [
- 112272535095293,
- 112582705942171,
- 112272535095293,
- 115280095190773,
- 115797848077099,
- 1099726899285419]
-
- def is_prime(n):
- if n < 2:
- return False
- if n == 2:
- return True
- if n % 2 == 0:
- return False
-
- sqrt_n = int(math.floor(math.sqrt(n)))
- for i in range(3, sqrt_n + 1, 2):
- if n % i == 0:
- return False
- return True
-
- def main():
- with concurrent.futures.ProcessPoolExecutor() as executor:
- for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
- print('%d is prime: %s' % (number, prime))
-
- if __name__ == '__main__':
- main()
Future 类将可调用对象封装为异步执行。Future 实例由 Executor.submit() 创建。
class concurrent.futures.Future
将可调用对象封装为异步执行。Future 实例由 Executor.submit() 创建,除非测试,不应直接创建。
主要的方法和属性有:
方法和属性名 | 说明 |
cancel() | 尝试取消调用。 如果调用正在执行或已结束运行不能被取消则该方法将返回 False ,否则调用会被取消并且该方法将返回 True 。 |
cancelled() | 如果调用成功取消返回 True 。 |
running() | 如果调用正在执行而且不能被取消那么返回 True 。 |
done() | 如果调用已被取消或正常结束那么返回 True 。 |
result(timeout=None) | 返回调用所返回的值。 如果调用尚未完成则此方法将等待至多 timeout 秒。 如果调用在 timeout 秒内仍未完成,则将引发 TimeoutError。 timeout 可以为整数或浮点数。 如果 timeout 未指定或为 None,则不限制等待时间。 如果 future 在完成前被取消则 CancelledError 将被触发。 如果调用引发了一个异常,这个方法也会引发同样的异常。 |
exception(timeout=None) | 返回调用所引发的异常。 如果调用尚未完成则此方法将等待至多 timeout 秒。 如果调用在 timeout 秒内仍未完成,则将引发 TimeoutError。 timeout 可以为整数或浮点数。 如果 timeout 未指定或为 None,则不限制等待时间。 如果 future 在完成前被取消则 CancelledError 将被触发。 如果调用正常完成那么返回 None。 |
add_done_callback(fn) | 附加可调用 fn 到 future 对象。当 future 对象被取消或完成运行时,将会调用 fn,而这个 future 对象将作为它唯一的参数。 加入的可调用对象总被属于添加它们的进程中的线程按加入的顺序调用。如果可调用对象引发一个 Exception 子类,它会被记录下来并被忽略掉。如果可调用对象引发一个 BaseException 子类,这个行为没有定义。如果 future 对象已经完成或已取消,fn 会被立即调用。 |
set_running_or_notify_cancel() | 这个方法只可以在执行关联 Future 工作之前由 Executor 实现调用或由单测试调用。 如果此方法返回 False 则 Future 已被取消,即 Future.cancel() 已被调用并返回 True。 任何等待 Future 完成 (即通过 as_completed() 或 wait()) 的线程将被唤醒。 如果此方法返回 True 则 Future 没有被取消并已被置为正在运行的状态,即对 Future.running() 的调用将返回 True。 这个方法只可以被调用一次并且不能在调用 Future.set_result() 或 Future.set_exception() 之后再调用。 |
set_result(result) | 设置将 Future 关联工作的结果给 result 。 这个方法只可以由 Executor 实现和单元测试使用。 |
set_exception(exception) | 设置 Future 关联工作的结果给 Exception exception 。 这个方法只可以由 Executor 实现和单元测试使用。 |
concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED)
等待由 fs 指定的 Future 实例(可能由不同的 Executor 实例创建)完成。 重复传给 fs 的 future 会被移除并将只返回一次。 返回一个由集合组成的具名 2 元组。 第一个集合的名称为 done,包含在等待完成之前已完成的 future(包括正常结束或被取消的 future)。 第二个集合的名称为 not_done,包含未完成的 future(包括挂起的或正在运行的 future)。
timeout 可以用来控制返回前最大的等待秒数。 timeout 可以为 int 或 float 类型。 如果 timeout 未指定或为 None ,则不限制等待时间。
return_when 指定此函数应在何时返回。它必须为以下常数之一:
常量 | 描述 |
---|---|
| 函数将在任意可等待对象结束或取消时返回。 |
| 函数将在任意可等待对象因引发异常而结束时返回。当没有引发任何异常时它就相当于 |
| 函数将在所有可等待对象结束或取消时返回。 |
concurrent.futures.as_completed(fs, timeout=None)
返回一个包含 fs 所给出的 Future 实例(可能由不同的 Executor 实例创建)的迭代器,这些实例会在完成时产生 future 对象(包括正常结束或被取消的 future 对象)。 任何由 fs 给出的重复的 future 对象将只被返回一次。 任何在 as_completed() 被调用之前完成的 future 对象将优先被产生。 如果 __next__() 被调用并且在对 as_completed() 的原始调用 timeout 秒之后其结果仍不可用则所返回的迭代器将引发 TimeoutError。 timeout 可以为整数或浮点数。 如果 timeout 未指定或为 None,则不限制等待时间。