当前位置: 首页 > article >正文

《Python实战进阶》No42: 多线程与多进程编程详解(上)

No42: 多线程与多进程编程详解(上)


摘要

在现代软件开发中,性能优化是提升用户体验和系统效率的重要手段。Python 提供了强大的多线程与多进程编程工具,帮助开发者充分利用多核 CPU 和高效处理 I/O 密集型任务。本文将简要介绍 Python 中的 threadingmultiprocessing 模块,分析它们的核心概念、适用场景以及实战案例。通过本文的学习,你将掌握如何根据任务类型选择合适的并发模型,并实现高效的代码。
在这里插入图片描述


核心概念和知识点

1. GIL(全局解释器锁)的影响

  • GIL 的作用:Python 的 CPython 解释器通过 GIL 确保同一时间只有一个线程执行 Python 字节码。这使得多线程在计算密集型任务中性能受限。
  • 适用场景:由于 GIL 的限制,多线程更适合 I/O 密集型任务(如文件读写、网络请求),而多进程则适合计算密集型任务(如矩阵运算、图像处理)。

2. threading 模块与 multiprocessing 模块的区别

  • threading 模块
    • 基于线程实现并发。
    • 轻量级,线程间共享内存空间。
    • 受 GIL 限制,无法充分利用多核 CPU。
  • multiprocessing 模块
    • 基于进程实现并发。
    • 每个进程拥有独立的内存空间,避免 GIL 的限制。
    • 开销较大,但可充分利用多核 CPU。

3. 线程间通信与进程间通信

  • 线程间通信:通过共享变量或 queue.Queue 实现。
  • 进程间通信:通过 multiprocessing.Queuemultiprocessing.Pipe 实现。

4. AI 大模型相关性

  • 在 AI 大模型训练中:
    • 多进程:常用于数据加载与预处理,利用多核 CPU 加速数据管道。
    • 多线程:适用于非计算密集型任务,例如日志记录、监控等。

实战案例

案例 1:使用多线程实现文件批量下载

问题描述

假设我们需要从多个 URL 下载文件,这些任务主要涉及网络 I/O 操作,因此适合使用多线程。

代码实现
import threading
import requests
from queue import Queue

# 共享队列存储下载任务
download_queue = Queue()

# 模拟 URL 列表
urls = [
    "https://example.com/file1.txt",
    "https://example.com/file2.txt",
    "https://example.com/file3.txt",
    "https://example.com/file4.txt"
]

def download_file(url):
    """下载单个文件"""
    try:
        response = requests.get(url)
        filename = url.split("/")[-1]
        with open(filename, "wb") as file:
            file.write(response.content)
        print(f"下载完成: {filename}")
    except Exception as e:
        print(f"下载失败: {url}, 错误: {e}")

def worker():
    """工作线程函数"""
    while not download_queue.empty():
        url = download_queue.get()
        download_file(url)
        download_queue.task_done()

# 将 URL 添加到队列
for url in urls:
    download_queue.put(url)

# 创建并启动线程
threads = []
for _ in range(4):  # 启动 4 个线程
    thread = threading.Thread(target=worker)
    thread.start()
    threads.append(thread)

# 等待所有线程完成
for thread in threads:
    thread.join()

print("所有文件下载完成!")
输入输出
  • 输入:URL 列表。
  • 输出
    下载完成: file1.txt
    下载完成: file2.txt
    下载完成: file3.txt
    下载完成: file4.txt
    所有文件下载完成!
    

案例 2:使用多进程加速图像处理任务

问题描述

假设我们需要对一批图像进行灰度化处理,这是一个计算密集型任务,适合使用多进程。

代码实现
from multiprocessing import Pool
from PIL import Image
import os

# 图像文件夹路径
image_dir = "./images"

# 输出文件夹路径
output_dir = "./output_images"
os.makedirs(output_dir, exist_ok=True)

def process_image(image_path):
    """将图像转换为灰度图像"""
    try:
        img = Image.open(image_path)
        gray_img = img.convert("L")
        output_path = os.path.join(output_dir, os.path.basename(image_path))
        gray_img.save(output_path)
        print(f"处理完成: {output_path}")
    except Exception as e:
        print(f"处理失败: {image_path}, 错误: {e}")

if __name__ == "__main__":
    # 获取图像文件列表
    image_files = [os.path.join(image_dir, f) for f in os.listdir(image_dir) if f.endswith(".jpg")]

    # 使用多进程池加速处理
    with Pool(processes=4) as pool:  # 启用 4 个进程
        pool.map(process_image, image_files)

    print("所有图像处理完成!")
输入输出
  • 输入:包含图像文件的文件夹。
  • 输出
    处理完成: ./output_images/image1.jpg
    处理完成: ./output_images/image2.jpg
    处理完成: ./output_images/image3.jpg
    所有图像处理完成!
    

总结

  • 多线程:适合 I/O 密集型任务,如文件下载、网络请求等。由于 GIL 的限制,不适用于计算密集型任务。
  • 多进程:适合计算密集型任务,如图像处理、矩阵运算等。通过独立的内存空间和多核 CPU 支持,能够显著提升性能。
  • 合理选择:根据任务特性选择合适的并发模型,可以有效提升程序的运行效率。

扩展思考

  1. 结合分布式计算框架扩展多进程能力
    使用分布式计算框架(如 Ray 或 Dask)可以突破单机限制,实现更大规模的并发计算。例如,Ray 提供了轻量级的任务调度和分布式执行能力,非常适合大规模数据处理任务。

  2. GPU 加速与多进程编程的结合点
    在深度学习领域,GPU 加速已经成为主流。结合多进程编程,可以进一步优化数据预处理和模型训练流程。例如,使用 multiprocessing 并行加载数据,同时利用 GPU 进行模型训练。

  3. 异步编程的补充
    对于复杂的 I/O 密集型任务,可以考虑使用 asyncio 实现异步编程,避免多线程的复杂性和开销。


通过本集的学习,相信你已经掌握了 Python 中多线程与多进程编程的核心知识,并能够将其应用于实际项目中。下一集我们将探讨如何结合异步编程与并发模型,进一步提升程序性能!


http://www.kler.cn/a/595252.html

相关文章:

  • 【漫话机器学习系列】153.残差平方和(Residual Sum of Squares, RSS)
  • LeetCode 2680.最大或值:位运算
  • 如何在IPhone 16Pro上运行python文件?
  • 【UI设计】一些好用的免费图标素材网站
  • el-select下拉框,搜索时,若是匹配后的数据有且只有一条,则当失去焦点时,默认选中该条数据
  • ngx_http_conf_port_t
  • 每天学一个 Linux 命令(6):shutdown
  • QT学习笔记3
  • ⭐算法OJ⭐二叉树的后序遍历【树的遍历】(C++实现)Binary Tree Postorder Traversal
  • 强大的AI网站推荐(第二集)—— V0.dev
  • 解释下Cumulative Layout Shift (CLS)以及如何优化?
  • JavaScript(JS)单线程影响速度
  • Linux:gsd-account进程异常内存泄漏排查
  • 背包问题——多重背包(C语言)
  • go中的文件、目录的操作
  • vscode/cursor中python运行路径设置 模块导入问题
  • 【AI论文】Being-0:一款配备视觉-语言模型与模块化技能的人形机器人智能体
  • TK矩阵系统:高效管理与智能化操作平台
  • 故事讲解设计模式:观察者模式
  • Kotlin标准函数库学习