0

0

使用线程池并发执行子进程以提高效率

DDD

DDD

发布时间:2025-09-14 19:15:24

|

562人浏览过

|

来源于php中文网

原创

使用线程池并发执行子进程以提高效率

本文旨在介绍如何使用 Python 的 subprocess 模块并发执行多个子进程,并通过线程池来显著提高程序的执行效率。我们将分析常见的使用 subprocess.Popen 和 .communicate() 方法的场景,并提供使用 ThreadPool 并发等待子进程完成的示例代码。

在使用 subprocess 模块执行多个子进程时,一个常见的误解是 Popen 函数会阻塞程序的执行。实际上,Popen 函数是非阻塞的,它会立即返回一个 Popen 对象,允许程序继续执行。然而,Popen 对象的 communicate() 方法是阻塞的,它会等待子进程执行完毕并返回其输出。如果在循环中依次调用 communicate() 方法,实际上会导致子进程按顺序执行,从而降低程序的效率。

为了解决这个问题,可以使用线程池来并发等待子进程完成。线程池可以创建多个线程,每个线程负责等待一个子进程完成。这样,多个子进程可以同时运行,从而提高程序的执行效率。

下面是一个使用线程池并发等待子进程完成的示例代码:

import subprocess
import logging
from multiprocessing.pool import ThreadPool

logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)

def runShowCommands(cmdTable) -> dict:
    """return a dictionary of captured output from commands defined in cmdTable."""
    procOutput = {}  # dict to store the output text from show commands
    procHandles = {}
    for cmd, command in cmdTable.items():
        try:
            log.debug(f"running subprocess {cmd} -- {command}")
            procHandles[cmd] = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        except Exception as e:
            log.error(f"Error launching subprocess {cmd}: {e}")
            continue

    def handle_proc_stdout(handle):
        try:
            proc = procHandles[handle]
            stdout, stderr = proc.communicate(timeout=180)
            procOutput[handle] = stdout.decode("utf-8")  # turn stdout portion into text
            log.debug(f"subprocess returned {handle}")
            if stderr:
                log.error(f"subprocess {handle} returned stderr: {stderr.decode('utf-8')}")
        except subprocess.TimeoutExpired:
            log.error(f"subprocess {handle} timed out")
            proc.kill() # Terminate the process
        except Exception as e:
            log.error(f"Error handling subprocess {handle}: {e}")


    threadpool = ThreadPool()
    threadpool.map(handle_proc_stdout, procHandles.keys())
    threadpool.close()
    threadpool.join()

    return procOutput

if __name__ == '__main__':
    cmdTable = {
        'himom': "echo hi there momma",
        'goodbye': "echo goodbye",
        'date': "date",
        'sleep': "sleep 2 && echo slept"
    }

    output = runShowCommands(cmdTable)

    for cmd, out in output.items():
        print(f"Output from {cmd}:\n{out}")

代码解释:

  1. runShowCommands(cmdTable) 函数:

    网胜B2B电子商务系统蓝色风格 2008 SP6.2 普及版
    网胜B2B电子商务系统蓝色风格 2008 SP6.2 普及版

      websenB2B是一套经过完善设计的B2B行业网站程序,是windows nt系列环境下最佳的B2B行业网产站解决方案。精心设计的架构与功能机制,适合从个人到企业各方面应用的要求,为您提供一个安全、稳定、高效、易用而快捷的行业网站商务系统。分普及版和商业版等不同版本。一、网胜B2B电子商务系统SP6.2蓝色风格普及版本升级功能说明:1、邮件群发功能:可以选择某一级别的会员,并放入支持html

    下载
    • 接受一个字典 cmdTable,其中键是命令的名称,值是要执行的命令字符串。
    • 创建一个空字典 procOutput 来存储每个命令的输出。
    • 创建一个空字典 procHandles 来存储每个 Popen 对象。
    • 循环遍历 cmdTable 中的每个命令:
      • 使用 subprocess.Popen 启动子进程,并将 stdout 和 stderr 重定向到管道。 shell=True 允许直接执行字符串命令,但要注意安全性。
      • 将 Popen 对象存储在 procHandles 字典中,键是命令名称。
    • 定义一个内部函数 handle_proc_stdout(handle):
      • 此函数负责处理单个子进程的输出。
      • 使用 procHandles[handle].communicate(timeout=180) 获取子进程的输出,并设置超时时间为 180 秒。
      • 将输出解码为 UTF-8 字符串,并将其存储在 procOutput 字典中。
      • 记录子进程返回的消息。
      • 处理 TimeoutExpired 异常,如果子进程超时,则记录错误并终止该进程。
      • 处理其他异常,如果发生任何其他错误,则记录错误消息。
    • 创建一个 ThreadPool 对象。
    • 使用 threadpool.map(handle_proc_stdout, procHandles.keys()) 将 handle_proc_stdout 函数应用于 procHandles 字典中的每个键(命令名称)。 这会在线程池中并行执行 handle_proc_stdout 函数。
    • 调用 threadpool.close() 以防止向线程池提交更多任务。
    • 调用 threadpool.join() 以等待所有线程完成。
    • 返回 procOutput 字典。
  2. if __name__ == '__main__': 块:

    • 创建一个示例 cmdTable 字典。
    • 调用 runShowCommands(cmdTable) 执行命令并获取输出。
    • 循环遍历 output 字典,并打印每个命令的输出。

注意事项:

  • 超时处理: communicate(timeout=180) 设置了超时时间,防止子进程无限期运行。如果子进程在指定时间内未完成,将引发 TimeoutExpired 异常,并且该进程将被终止。
  • 错误处理: 代码包含 try...except 块,用于捕获可能发生的异常,例如子进程启动失败或超时。
  • 线程安全: 确保在多线程环境中访问和修改共享资源(例如 procOutput 字典)是线程安全的。 在此示例中,由于每个线程都写入不同的键,因此字典的写入操作是线程安全的。
  • 资源限制: 创建过多的线程可能会消耗大量系统资源。 线程池的大小应根据系统资源和任务的性质进行调整。
  • 安全性: 使用 shell=True 执行命令时,需要注意命令注入的风险。 确保命令字符串来自可信来源,或者对输入进行适当的转义。
  • 日志记录: 使用 logging 模块记录程序的运行状态,方便调试和排错。

总结:

通过使用线程池,可以并发执行多个子进程,从而显著提高程序的执行效率。 在处理大量并发任务时,线程池是一种非常有用的技术。 请记住考虑超时处理、错误处理、线程安全性和资源限制等因素,以确保程序的正确性和稳定性。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

778

2023.08.22

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

298

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1501

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

624

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

633

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

589

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

172

2025.07.29

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

1

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 3.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号