前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >记录Python 调用 subprocess.Popen 卡死解决办法

记录Python 调用 subprocess.Popen 卡死解决办法

作者头像
用户4945346
发布2024-02-17 15:49:12
3540
发布2024-02-17 15:49:12
举报
文章被收录于专栏:pythonista的日常pythonista的日常

subprocess.Popen 是 Python 中用于执行外部命令或程序的模块之一。它提供了创建子进程并与之交互的灵活方式。以向 subprocess.Popen 传递一个命令字符串或命令列表,它将调用操作系统的 shell 来执行该命令。

项目中需要在 Python 的代码中执行一些系统指令,例如调用项目中的某个可执行程序,所以就使用了 subprocess.Popen 方法。

源代码如下:

代码语言:javascript
复制
def subprocess_popen_cmd(cmds, cwd=None):
    if isinstance(cmds, list):
        cmds = " ".join(cmds)
    p = subprocess.Popen(
        cmds,
        stdout=subprocess.PIPE,
        shell=True,
        executable="/bin/bash",
        stderr=subprocess.STDOUT,
        universal_newlines=True,
        cwd=cwd,
    )
    logging.info("subprocess_popen_cmd start. pid:%d cmds:%r", p.pid, cmds)
    while p.poll() is None:
        data = p.stdout.readline()
        data = data.strip()
        if data:
            logging.info(data)
    logging.info(
        "subprocess_popen_cmd end. pid:%d, returncode:%d cmds:%r",
        p.pid,
        p.returncode,
        cmds,
    )
    if p.returncode != 0:
        raise Exception(f"subprocess_popen_cmd had error!{cmds}")

这段代码是一个 Python 函数,用于执行外部命令并捕获其输出。接收传入的系统命令,使用 subprocess.Popen 函数创建子进程来执行指定的命令。设置了一些参数来配置子进程的执行环境,具体包括:

stdout=subprocess.PIPE:将子进程的标准输出连接到管道,以便后续读取输出。

shell=True:表示通过系统的 shell 来执行命令,可以使用命令的通配符、管道等功能。

executable="/bin/bash":指定要执行的 shell 程序,这里是 /bin/bash。

stderr=subprocess.STDOUT:将子进程的标准错误输出合并到标准输出中。

universal_newlines=True:将输入和输出转换为文本模式,而不是字节模式。

cwd=cwd:设置子进程的工作目录。

如果调用的shell命令本身在执行之后会突然出现很多输出,则这个时候可能会导致hang在那里,表现就是卡死了,程序也不往下走,也不会报错。。。

原因就是:PIPE本身可容纳的量比较小,所以程序会卡死,所以一大堆内容输出过来的时候,会导致PIPE不足够处理这些内容

实际我的业务需求并不关心程序执行过程中的输出,只要知道最后的执行结果即可,使用上面的 subprocess.Popen 有些冗余,所以我改成了使用 subprocess.run 。修改后的代码:

代码语言:javascript
复制
def subprocess_popen_cmd(cmds, cwd=None):
    if isinstance(cmds, list):
        cmds = " ".join(cmds)

    print("cmds---subprocess.ru---", cmds)

    try:
        subprocess.run(
            cmds,
            shell=True,
            executable="/bin/bash",
            check=True,
            cwd=cwd  # 指定子进程的工作目录
        )
    except subprocess.CalledProcessError as e:
        raise Exception(f"Error executing cmd: {cmds}\n{e.stderr.decode('utf-8')}")

subprocess.Popen 和 subprocess.run 是 Python 中用于执行外部命令的两个常用函数,它们之间有几个重要的区别:

subprocess.Popen 是一个更底层的接口,允许你以更灵活的方式创建子进程并与之交互。它返回一个 Popen 对象,通过该对象你可以控制子进程的输入、输出和状态。

subprocess.run 是一个更高级别的函数,封装了一系列常用的子进程操作,例如执行命令并等待其完成,然后返回一个包含执行结果的 CompletedProcess 对象。

subprocess.Popen 提供了更多的灵活性,但需要你手动管理子进程的输入、输出和状态,因此在处理更复杂的子进程交互时可能需要更多的工作。综上所述,subprocess.run 适合简单地执行外部命令并获取输出;subprocess.Popen 适合更灵活地控制子进程,以及处理更复杂的子进程交互,注意不要使用 stdout=subprocess.PIPE

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-02-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 pythonista的日常 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档