并发编程基础:从线程到进程的Python实践

Langchain系列文章目录

01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!

python系列文章目录

01-Python 基础语法入门:从变量到输入输出,零基础也能学会!
02-Python 流程控制终极指南:if-else 和 for-while深度解析
03-Python 列表与元组全攻略:从新手到高手的必备指南
04-Python 字典与集合:从入门到精通的全面解析
05-Python函数入门指南:从定义到应用
06-Python 函数高级特性:从默认参数到闭包的全面解析
07-Python 模块与包:从零到自定义的全面指南
08-Python异常处理:从入门到精通的实用指南
09-Python 文件操作:从零基础到日志记录实战
10-Python面向对象编程入门:从类与对象到方法与属性
11-Python类的方法与属性:从入门到进阶的全面解析
12-Python继承与多态:提升代码复用与灵活性的关键技术
13-掌握Python魔法方法:如何用__add__和__len__自定义类的行为
14-python面向对象编程总结:从基础到进阶的 OOP 核心思想与设计技巧
15-掌握 Python 高级特性:深入理解迭代器与生成器
16-用 Python 装饰器提升效率:日志与权限验证案例
17-再也不怕资源泄漏!Python 上下文管理器,with语句全攻略
18-Python 标准库必备模块:math、random、os、json 全解析
19-Python 性能优化:从入门到精通的实用指南
20-Python内存管理与垃圾回收全解析
21-Python 代码调试与测试:从 pdb 到 TDD 的全面指南
22-Python 代码风格终极指南:从 PEP 8 到最佳实践全解析
23-Python实现网络通信:Socket模块与TCP/IP协议全解析
24-Python如何用requests库实现HTTP请求与响应?从零到实战全解析
25-并发编程基础:从线程到进程的Python实践


前言

在现代编程中,并发编程是一项不可或缺的技能。无论是为了提升程序的运行效率,还是充分利用多核处理器的性能,掌握并发编程都能让你的代码更上一层楼。Python 提供了强大的工具,如 threadingmultiprocessing 模块,让开发者能够轻松实现多线程和多进程编程。

本文将围绕并发编程基础展开,从线程与进程的概念入手,逐步深入到如何在 Python 中使用 threading 模块实现多线程,以及使用 multiprocessing 模块实现多进程。文章将通过通俗易懂的语言、清晰的代码示例和实际应用场景,帮助初学者快速入门,同时为进阶读者提供实用的技术参考。


一、并发编程概述

并发编程的核心在于如何高效地处理多个任务。本节将从基础概念出发,带你理解线程和进程的本质,以及它们在 Python 中的作用。

1.1 线程与进程的概念

线程和进程是并发编程的两个基本单位。理解它们的定义和区别,是掌握后续技术的基础。

1.1.1 什么是进程?

进程(Process)是操作系统分配资源的最小单位。每个进程都有独立的内存空间和系统资源。简单来说,你可以把进程想象成一个运行中的程序。比如,当你打开一个浏览器,它就是一个进程;再打开一个音乐播放器,又是一个新进程。

由于进程之间内存独立,数据交换需要通过管道或队列等机制,虽然安全性高,但通信成本也相对较大。

1.1.2 什么是线程?

线程(Thread)是进程内部的执行单元。一个进程可以包含多个线程,这些线程共享进程的内存和资源。打个比方,如果进程是一个工厂,那么线程就是工厂里的工人,多个工人共享工厂的设备,分工协作完成任务。

线程之间的通信更简单,但也容易因为共享资源而产生冲突,需要额外的同步机制来管理。

1.1.3 线程与进程的区别

以下是线程和进程的主要区别,方便大家快速记忆:

特性进程线程
资源分配独立内存空间共享进程的内存空间
通信方式需要特定机制(如队列)直接共享变量,通信简单
创建开销较大,涉及资源分配较小,基于现有进程
调度单位操作系统调度CPU 调度

1.2 并发与并行的区别

在学习并发编程时,经常会听到“并发”和“并行”两个词,它们有何不同?

  • 并发(Concurrency):指在同一时间段内,多个任务交替执行,看起来像是同时发生。比如,你一边听音乐一边写代码,CPU 在两个任务间快速切换。
  • 并行(Parallelism):指在同一时刻,多个任务真正同时执行。这需要多核 CPU 或多台机器支持。

在 Python 中,threading 实现的是并发,而 multiprocessing 可以实现并行,因为它能利用多核 CPU。


二、使用 threading 模块实现多线程

Python 的 threading 模块是实现多线程的利器。它简单易用,适合处理 I/O 密集型任务。本节将从创建线程到线程同步,带你逐步掌握多线程编程。

2.1 创建线程

创建线程有两种常用方式,下面逐一介绍。

2.1.1 使用 Thread 类直接创建

你可以通过 threading.Thread 类创建一个线程,指定一个目标函数作为线程的任务。

import threading

def say_hello():
    print(f"Hello from {threading.current_thread().name}")

# 创建线程,指定目标函数
thread = threading.Thread(target=say_hello, name="MyThread")
# 启动线程
thread.start()
# 等待线程结束
thread.join()

代码解析

  • target=say_hello:指定线程要执行的函数。
  • name="MyThread":给线程取个名字,便于调试。
  • start():启动线程,线程开始运行。
  • join():主线程等待子线程结束。

运行结果可能是:

Hello from MyThread

2.1.2 通过继承 Thread 类创建

另一种方式是继承 threading.Thread 类,重写 run 方法。

import threading

class MyThread(threading.Thread):
    def run(self):
        print(f"Hello from {self.name}")

# 创建线程实例
thread = MyThread(name="CustomThread")
# 启动线程
thread.start()
# 等待线程结束
thread.join()

这种方式更灵活,适合需要封装线程逻辑的场景。

2.2 线程同步

多线程共享资源时,可能会出现“竞态条件”(多个线程同时修改同一变量,导致结果不可预测)。我们需要使用锁(Lock)来同步线程。

2.2.1 使用 Lock 避免竞态条件

下面是一个例子:两个线程同时对一个全局变量 counter 进行累加。

import threading

counter = 0
lock = threading.Lock()

def increment():
    global counter
    for _ in range(100000):
        # 获取锁
        lock.acquire()
        counter += 1
        # 释放锁
        lock.release()

# 创建两个线程
t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=increment)

# 启动线程
t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()

print(f"Final counter: {counter}")

运行结果

Final counter: 200000

代码解析

  • lock.acquire():获取锁,确保同一时刻只有一个线程操作 counter
  • lock.release():释放锁,让其他线程继续执行。
  • 如果不加锁,counter 的最终值可能会小于 200000,因为线程会“抢着”修改它。

2.2.2 使用 with 简化锁操作

为了避免忘记释放锁,Python 支持用 with 语句管理锁:

def increment():
    global counter
    for _ in range(100000):
        with lock:
            counter += 1

这种写法更简洁,自动处理锁的获取和释放。

2.2.3 常见问题:死锁

使用锁时要小心死锁(Deadlock),即多个线程互相等待对方释放锁,导致程序卡住。例如:

lock1 = threading.Lock()
lock2 = threading.Lock()

def thread1():
    with lock1:
        with lock2:
            print("Thread 1")

def thread2():
    with lock2:
        with lock1:
            print("Thread 2")

解决方法

  • 确保所有线程以相同的顺序获取锁。
  • 使用超时机制,如 lock.acquire(timeout=1)

三、使用 multiprocessing 模块实现多进程

与线程不同,进程有独立的内存空间,适合 CPU 密集型任务。Python 的 multiprocessing 模块让多进程编程变得简单。

3.1 创建进程

创建进程的方式与线程类似,也有两种常用方法。

3.1.1 使用 Process 类直接创建

from multiprocessing import Process

def work():
    print(f"Working in {Process().name}")

# 创建进程
p = Process(target=work)
# 启动进程
p.start()
# 等待进程结束
p.join()

运行结果

Working in Process-1

3.1.2 通过继承 Process 类创建

from multiprocessing import Process

class MyProcess(Process):
    def run(self):
        print(f"Working in {self.name}")

# 创建进程实例
p = MyProcess()
# 启动进程
p.start()
# 等待进程结束
p.join()

3.2 进程间通信

由于进程间内存不共享,需要通过特定机制(如队列)传递数据。

3.2.1 使用 Queue 实现通信

下面是一个生产者-消费者模型的例子:

from multiprocessing import Process, Queue

def producer(queue):
    for i in range(5):
        queue.put(i)
        print(f"Produced {i}")

def consumer(queue):
    while True:
        item = queue.get()
        if item is None:
            break
        print(f"Consumed {item}")

# 创建队列
queue = Queue()
# 创建进程
p1 = Process(target=producer, args=(queue,))
p2 = Process(target=consumer, args=(queue,))

# 启动进程
p1.start()
p2.start()

# 等待生产者结束
p1.join()
# 发送结束信号
queue.put(None)
# 等待消费者结束
p2.join()

运行结果

Produced 0
Produced 1
Produced 2
Produced 3
Produced 4
Consumed 0
Consumed 1
Consumed 2
Consumed 3
Consumed 4

代码解析

  • queue.put(i):生产者将数据放入队列。
  • queue.get():消费者从队列取出数据。
  • queue.put(None):用 None 作为结束信号。

3.2.2 常见问题:队列阻塞

如果队列为空,queue.get() 会阻塞进程。解决方法是设置超时:

item = queue.get(timeout=1)  # 等待1秒,超时抛出异常

四、总结

本文从并发编程的基础知识入手,详细讲解了线程和进程的概念,以及在 Python 中使用 threading 模块实现多线程和 multiprocessing 模块实现多进程的技术。通过丰富的代码示例和实际场景,你应该已经掌握了以下要点:

  • 线程适合 I/O 密集型任务,多进程适合 CPU 密集型任务。
  • 使用锁(Lock)解决线程间的竞态条件。
  • 使用队列(Queue)实现进程间通信。

并发编程是 Python 开发者进阶的必备技能。希望本文能为你提供一个清晰的学习路径,鼓励你进一步探索异步编程等高级主题!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴师兄大模型

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值