Python标准库 subprocess 模块多进程编程详解

1. Subprocess模块介绍

1.1 基本功能

  • subprocess 模块,允许生成新的进程执行命令行指令,python程序,以及其它语言编写的应用程序, 如 java, c++,rust 应用等。
  • subprocess可连接多个进程的输入、输出、错误管道,并且获取它们的返回码。
  • asyncio也支持subprocess.

许多知名库都在使用此模块创建进程,以及做为跨语言粘合工具。典型如ansible, celery,selenium 等。

1.2 与multiprocessing主要区别

  • multiprocessing 创建的子进程的代码也需要开发者实现。
  • subprocess创建的子进程主要用于运行已有指令或应用。

根据上述主要区别,不难推断出, subprocess创建子进程的用途,主要用于执行非python的外部程序,如windows/linux 命令,C程序,Java程序等,而且可以实现进程通信,多进程管道,以及异步执行等。

1.3 subprocess 模块主要掌握知识点

(1)run()方法创建子进程
(2)stdin, stdout,stderr 的配置,以及管道使用
(3)Popen API使用。
(4)进程之间通信

2 使用run() 方法创建子进程

2.1 run() 语法

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, text=None, env=None)

返回值类型
subprocess.CompletedProcess
主要参数

  • args:表示要执行的命令。必须是以字符串为元素的 list or tuple 。
  • stdin、stdout 和 stderr:子进程的标准输入、输出和错误。其值可以是 subprocess.PIPE、subprocess.DEVNULL、一个已经存在的文件描述符、已经打开的文件对象或者 None。subprocess.PIPE 表示为子进程创建新的管道。subprocess.DEVNULL 表示使用 os.devnull。默认使用的是 None,表示什么都不做。
  • encoding: 如果指定了该参数,则 stdin、stdout 和 stderr 可以接收字符串数据,并以该编码方式编码。否则只接收 bytes 类型的数据。
  • shell:如果该参数为 True,将通过操作系统的 shell 执行指定的命令。
  • check: 如check=true, 当进程退出码为非0时,将生成 CalledProcessError 异常

2.2 返回对象CompletedProcess的主要属性与方法:

主要属性

  • args 执行指令list or tuple
  • returncode 执行完子进程状态码,为0则表明它已经运行完毕,若值为负值 ,表明子进程被终。 为None表示未执行完成。
  • stdout 输出内容,
  • stderr error输出内容
    方法
  • check_returncode() 如果 returncode 是非零值, 将生成异常 CalledProcessError.

示例

>>> 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

2.3 什么是 stdin, stdout, stderr?

OS 执行一个shell命令,会自动打开三个标准文件

  • 标准输入文件(stdin),通常对应终端的键盘;
  • 标准输出文件(stdout), 标准错误输出文件(stderr),这两个文件都对应终端的屏幕。

进程的I/O操作

  • 进程将从标准输入文件中得到输入数据
  • 将正常输出数据输出到标准输出文件,
  • 将错误信息送到标准错误文件中。

标准输入、输出可以重定向, 从ubuntu linux为例

  • 输入重定向: wc < abc.txt, 输入重定向为由文件读入。
  • 输出重定向: tail a.log > abc.txt , 输出重定向到abc.txt , >> 为追加模式
  • 错误输出重定向: 用 2> 文件名 表示 ,
    如 python demo.py 2>&1, 将把标准错误输出重定向到输出stdout
    使用“ >/dev/null ”符号,将命令执行结果重定向到空设备中,也就是不显示任何信息。

有时host进程可能修改了输入/输出设备,subprocess将继承,可以手工指定I/O设备
在这里插入图片描述

windows用run()时,args指令中前面要加cmd.exe做为执行器
cmdTuple =(“cmd.exe”, “/C”, r"del d:\output*.png")
subprocess.run(cmdTuple)

如果运行dos命令,前两个参数为 “cmd.exe”, “/C”, 否则报错。
subprocess.run([‘cmd’, ‘/C’, ‘dir D:\app’])

也可使用powshell 做执行器, 其格式如下:
subprocess.run([“powershell”, “-Command”, “dir D:\app”])

运行 .py文件,无须加 cmd.exe
subprocess.run([‘python’, ‘demo.py’, ‘5’]) 其中5为参数

指令也可以用字符串的形式,用shlex来解析为list
import shlex
print( shlex.split(“python subp_timer.py 5”))
subprocess.run(shlex.split(“python subp_timer.py 5”))
output:
[‘python’, ‘subp_timer.py’, ‘5’]
Starting timer of 5 seconds
…Done!

linux 使用默认shell做为执行器,也可以指定如用 ‘bash’
subprocess.run([“bash”, “-c”, “ls /usr/bin | grep pycode”])

3.Pipe 使用

Pipe 即管道,可以将两个进程连接起来:上1个进程的stdout 可以做为下1个进程的输入

cp1 = subprocess.run(
['cmd.exe','/C','dir /A:D /B','D:\workplace'],
stdout=subprocess.PIPE
)
print(cp1.stdout.decode('utf-8'))

cp2 = subprocess.run(
['cmd.exe','/C','find','/I','\"python\"'],
input=cp1.stdout,
stdout=subprocess.PIPE
)
print(cp2)

4.Popen API 使用

Popen 是 subprocess的核心,底层的子进程的创建和管理都靠它处理,它支持主程序与子进程之间通信。 run()方法只能用于一些简单场合,Popen()更加方便。

4.1 Popen对象的构造函数:

class subprocess.Popen(args, bufsize=-1, stdin=None, stdout=None, stderr=None, 
shell=False, cwd=None, env=None, *, encoding=None)

常用参数:

  • args:shell命令,可以是字符串或者序列类型(如:list,元组)
  • bufsize:缓冲区大小。当创建标准流的管道对象时使用,默认-1。 0:不使用缓冲区 1:表示行缓冲,仅当universal_newlines=True时可用,也就是文本模式 正数:表示缓冲区大小 负数:表示使用系统默认的缓冲区大小。
  • stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
  • shell:如果该参数为 True,将通过操作系统的 shell 执行指定的命令。通常使用False
  • cwd:用于设置子进程的当前目录。
  • env:用于指定子进程的环境变量。如果 env = None,子进程的环境变量将从父进程中继承。
  • encoding 为stdout的编码,指定后,可自动将bytes内容转为字符串

创建一个子进程,然后执行一个简单的命令:
实例

>>> import subprocess 
>>> p = subprocess.Popen('ls -l', shell=True) 
>>> total 164 
-rw-r--r-- 1 root root 133 Jul 4 16:25 admin-openrc.sh 
-rw-r--r-- 1 root root 268 Jul 10 15:55 admin-openrc-v3.sh ... 
>>> p.returncode
>>> p.wait() 0
>>> p.returncode
Popen(["/usr/bin/git", "commit", "-m", "Fixes a bug."])

4.2 Popen 对象支持context

with Popen(["ifconfig"], stdout=PIPE) as proc:
    log.write(proc.stdout.read())

4.3 Popen对象的方法与属性

  • Popen.poll()
    检查子进程是否已被终止。设置并返回returncode 属性。否则返回 None。
  • Popen.wait(timeout=None)
    等待子进程被终止。设置并返回returncode 属性。
    如果进程在 timeout 秒后未中断,抛出一个TimeoutExpired 异常,可以安全地捕获此异常并重新等待。
  • Popen.communicate(input=None, timeout=None) 与进程交互:将数据发送到 stdin。从 stdout 和 stderr 读取数据,
    communicate() 返回一个 (stdout_data, stderr_data) 元组。如果文件以文本模式打开则为字符串;否则为字节串。
proc = subprocess.Popen(...)
try:
outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
  • Popen.send_signal(signal) 发送OS信号
  • Popen.terminate(), Popen.kill() 终止、杀死进程

属性
args, stdin, stdout, stderr, pid, returncode

4.5 Popen.stdout的编码问题

stdout值为bytes 类型,查看时通常需要转为str, 但windows 命令返回的stdout编码类型可能不是utf-8. 需要使用chardet.detect( bytes_obj) 来检测

import chardet
import subprocess

cmd = ['cmd.exe','/C', 'ipconfig']
pp = subprocess.Popen(cmd, 
                      stdout=subprocess.PIPE, 
                      stderr=subprocess.PIPE)
out: bytes = pp.stdout.read()
encode = chardet.detect(out)['encoding']
print(encode)
print(out.decode(encode))

output:

PS D:\workplace\python\test1\multi_thread> py subp_2.py
GB2312

Windows IP 配置
...

5. 与子进程的通信

5.1 向子进程输入数据

方式1: 通过communicate(input=bytes_obj) 输入参数

process = subprocess.Popen(['cmd', '/C', 'findstr','example'], stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
# 使用input参数传递输入
input_data = b"Some input\n subprocess \n example line"
out, err = process.communicate(input=input_data)
print(out)

方式2: 通过Pipe向子进程输入数据: process.stdin.write()

process = subprocess.Popen(['cmd', '/C', 'findstr','example'], stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
# Write to the subprocess's standard input
process.stdin.write(b'first line \n 2:some example input\n third line\n')
# Close the input stream
process.stdin.close()
out, err = process.communicate()
print(out, err)

3)获取子进程的输出内容
方式1: 使用 process.communicate() 方法获取 output 与 error
out, err = process.communicate(), out, err 均为bytes 类型
方式2: 直接读 process.stdout 属性, 方式与读文件相同,

line = process.stdout.readline()
content = process.stdout.read() 

示例

# 读取子进程的输出
cmd = ["ping", "baidu.com"]
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

counter = 0
while True:
    # Read a line from the subprocess's stdout
    line = process.stdout.readline()
    
    # Check if the line is empty, indicating that the subprocess has finished
    if not line :
        break
    if counter > 3:
        print(f"terminate process {process.pid}")
        process.terminate()   # 强行终止进程
        break
    counter += 1
    print(process.poll())    # 检查进程是否结束
    # Process and print the line
    print(line, end='')

# Wait for the subprocess to finish and get its return code
return_code = process.wait(2)
print(f"Subprocess returned with exit code: {return_code}")
print(process.poll())

6. 子进程的异步执行

asyncio异步模块也提供了 subprocess 类, 好处是避开了GIL锁的限制, 运行速度显著提高

import asyncio

async def run(cmd):
    proc = await asyncio.create_subprocess_shell(
        cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE)

    stdout, stderr = await proc.communicate()

    print(f'[{cmd!r} exited with {proc.returncode}]')
    if stdout:
        print(f'[stdout]\n{stdout.decode()}')
    if stderr:
        print(f'[stderr]\n{stderr.decode()}')

async def main():
    await asyncio.gather(
        run('python subp_timer.py 2'),
    )

asyncio.run(main())

7. 其它功能

7.1 异常处理

子进程可能会遇到各种问题,建议使用如下处理异常的代码结构:

import subprocess
try:
    cmd = ["your_command_here"]
    process = subprocess.Popen(
cmd, 
stdout=subprocess.PIPE, 
stderr=subprocess.PIPE, 
text=True)
    stdout, stderr = process.communicate()
    print(stdout,stderr)
except subprocess.CalledProcessError as e:
    print(f'Subprocess failed with return code {e.returncode}')
except FileNotFoundError:
    print('Command not found')

7.2 常见问题排查

(1)命令不能运行,通常是args 列表有问题。 可先在terminal 测试
(2)命令行处理的文件与当前目录不同,
(3)进程block问题

  • communicate()方法是block方法,如果子进程未结束,运行communicate()会造成进程block, 应该使用stdout.read()来读取中间内容。
  • 如果进程有输入,需要注意提供输入stdin.write()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/130070.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024世亚国际软件博览会(世亚软博会)国内外知名软件厂商踊跃报名

作为亚洲软件展会的风向标&#xff0c;2024世亚国际软件博览会&#xff08;简称“世亚软博会”&#xff09;备受瞩目。近日&#xff0c;从组委会传来消息&#xff0c;目前招商工作已经接近半程&#xff0c;大批国内外软件厂商踊跃报名&#xff0c;展位销售异常火爆。 本届“世亚…

一台电脑使用多个gitee账号,以及提交忽略部分文件

目录 ​编辑 一&#xff1a;前言 二&#xff1a;解决方法 三&#xff1a;提交gitee时忽略文件 一&#xff1a;前言 在开发中&#xff0c;我们拥有不止一个 gitee 账号&#xff0c;通常而言一个是公司的&#xff0c;一个是私人的。有时候我们在公司写了一些自己的东西&#…

C++ set map 的模拟实现

set 的模拟实现 我们在很早之前就提到过&#xff0c;set 的底层数据结构是红黑树。红黑树的实现一般都是 key-value 的结构。但是我们在使用 set 的时候明明只传入了一个模板参数哇&#xff01;我们来看库中的实现&#xff1a; 我们可以看到&#xff0c;set 的模板参数 Key 就…

深入理解强化学习——多臂赌博机:乐观初始值

分类目录&#xff1a;《深入理解强化学习》总目录 目前为止我们讨论的所有方法都在一定程度上依赖于初始动作值 Q 1 ( a ) Q_1(a) Q1​(a)的选择。从统计学角度来说&#xff0c;这些方法&#xff08;由于初始估计值&#xff09;是有偏的。对于采样平均法来说&#xff0c;当所有…

Linux编译器——gcc/g++使用

前言&#xff1a; 在上一篇&#xff0c;我们学习了关于文本编辑器 vim 的全部知识&#xff0c;今天给大家带来的是关于Linux编译器—gcc/使用的详细介绍。 本文目录 &#xff08;一&#xff09;温习程序的产生的过程 1、前言 2、程序的产生过程 3、&#x1f31c;初步认识 gc…

中兴新支点国产系统将联合阿里龙蜥社区制定多项行业标准

近日&#xff0c;从中兴新支点操作系统官方了解到&#xff0c;中兴迎来阿里龙蜥社区理事长马涛一行人&#xff0c;并进行了深度交流。会上中兴新支点操作系统回顾了近一年在龙蜥社区的贡献和投入&#xff0c;并对双方未来的合作诉求和合作计划展开了讨论。会后&#xff0c;龙蜥…

代理IP的稳定性至关重要!真实技术案例引发深思

在当今的网络世界中&#xff0c;IP代理已经成为了我们保护个人隐私、开展各类互联网业务的重要工具。不过很多人在使用IP代理时&#xff0c;常常会忽视一个关键因素——代理IP的稳定性。今天我们就来谈谈这个问题&#xff0c;并分享一个真实的案例&#xff0c;希望能引起大家对…

linux粘滞位的介绍及使用

文章目录 1.粘滞位的引入2.粘滞位的使用 1.粘滞位的引入 首先看一个场景 已知 对目录无w权限时 无法进行目录中的文件的创建/删除操作但是普通用户通过sudo命令 以root身份创建一个文件 rw- r-- r-- 普通用户此时是other 没有w权限 但却可以删除 [root和普通用户在一个目录下时…

1210. 连号区间数(枚举)

题目&#xff1a; 1210. 连号区间数 - AcWing题库 思路&#xff1a;枚举 枚举一般是先暴力再优化。 注意&#xff1a;对于区间的枚举&#xff0c;一般是定一移一。固定任何一端移动另外一端均可以。但是此题为便于在枚举移动端的过程中确定最大最小&#xff0c;选择定左移右…

TinyMce富文本编辑器使用【详细】

TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有&#xff1a;UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。 TinyMCE的优势&#xff1a; 开源可商用&#xff0c;基于LGPL2.1插件丰富&#xff0c;自带插件基本涵盖日常…

css3文字环绕旋转

目录 固定数量文字环绕旋转不固定数量文字环绕旋转效果图 固定数量文字环绕旋转 <!-- 文字旋转测试 --> <template><div class"page"><div><div v-for"(item, index) in [...Array(20).keys()]" :key"index" style&…

104.c语言中的define的两个模糊点

1. define 是按照从上到下的顺序的 #define 必须先定义&#xff0c;否则报错 2.函数体内的define的影响 2.1 从定义开始的位置起&#xff0c;之后都有效 不受函数作用域的限制 #include <stdio.h>//int a[N] {0};#define N 100int a[N] {0}; //int b[X]; void abcd(v…

高等数学教材重难点题型总结(三)函数与极限

首先是考研大纲包含的内容&#xff1a; 1.理解并会用罗尔(Rolle)定理、拉格朗日(Lagrange)中值定理和泰勒(Taylor)定理&#xff0c;了解并会用柯西(Cauchy)中值定理. 2.掌握用洛必达法则求未定式极限的方法. 3.理解函数的极值概念&#xff0c;掌握用导数判断函数的单调性和求函…

基于SSM的在线作业管理系统 -octopus-master(源码+调试)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

虚幻5 删除C盘缓存及修改缓存路径

一.修改C盘缓存 C盘缓存路径为&#xff1a; C:\Users\xx(这里是你的用户名)\AppData\Local\UnrealEngine\Common\DerivedDataCache 注意&#xff0c;如果没有AppData文件夹&#xff0c;请依次点击查看-勾选显示隐藏的项目&#xff0c;即可 可删除里面的所有文件即可 二.修改…

leetcode 刷题 - 有效三角形个数 - 长度最小的子数组 - 无重复字符的最长子串

l611. 有效三角形的个数 - 力扣&#xff08;LeetCode&#xff09; 给定一个包含非负整数的数组 nums &#xff0c;返回其中可以组成三角形三条边的三元组个数。 示例 1:输入: nums [2,2,3,4] 输出: 3 解释:有效的组合是: 2,3,4 (使用第一个 2) 2,3,4 (使用第二个 2) 2,2,3示…

【Git】Git的GUI图形化工具ssh协议IDEA集成Git

一、GIT的GUI图形化工具 1、介绍 Git自带的GUI工具&#xff0c;主界面中各个按钮的意思基本与界面文字一致&#xff0c;与git的命令差别不大。在了解自己所做的操作情况下&#xff0c;各个功能点开看下就知道是怎么操作的。即使不了解&#xff0c;只要不做push操作&#xff0c;…

天翼云江西分公司副总经理彭越华一行莅临拓世科技集团指导考察,共绘蓝图开启智能新篇章

世界经济脉络在数字化的浪潮中迎来了新的生机&#xff0c;企业的成长轨迹正在智能化的力量下重新塑造。天翼云科技有限公司江西分公司副总经理彭越华一行的到访&#xff0c;为拓世科技集团带来了新的发展机遇。这场深入的交流&#xff0c;不仅预示着在科技创新和数字化转型的征…

【漏洞复现】BYTEVALUE智能流控路由器存在命令执行

【漏洞介绍】 百为智能流控路由器 /goform/webRead/open 路由的 ?path 参数存在有回显的命令注入漏洞。攻击者可通过该漏洞在服务器端执行命令&#xff0c;写入后门&#xff0c;获取服务器权限&#xff0c;从而获取路由器权限。 【指纹】 title”BYTEVALUE 智能流控路由器”…

Electron-vue出现GET http://localhost:9080/__webpack_hmr net::ERR_ABORTED解决方案

GET http://localhost:9080/__webpack_hmr net::ERR_ABORTED解决方案 使用版本解决方案解决总结 使用版本 以下是我解决此问题时使用的electron和vue等的一些版本信息 【附】经过测试 electron 的版本为 13.1.4 时也能解决 解决方案 将项目下的 .electron-vue/dev-runner.js…