threading 模块的类 Lock 的基本使用
1. 简介
在多线程应用中,某个资源被多个线程共享访问,线程通过使用锁独占该资源。需要独占访问的资源可能是:
打印机,线程在使用打印机时,不允许其它线程向打印机输出
共享变量,线程对这个变量进行读取访问时,不允许其它线程同时对这个变量进行读取访问
python 的 threading 模块提供了类 Lock 用于独占访问某个共享资源,类 Lock 提供了如下方法:
方法 功能
acquire() 获得锁,如果锁是空闲的,则立即返回;如果锁已经被其它线程占用了,则阻塞等待。
release() 释放锁,唤醒等待该锁的线程。
线程在独占使用某个资源前,需要调用 lock.acquire() 方法,使用完毕后,需要调用 lock.release() 方法,如下所示:
lock = threading.Lock()
lock.acquire()
独占访问某个资源
lock.release()
2. 数据竞争
当多个线程在读写某个共享变量时,其最终的结果依赖于线程的执行顺序,这种现象被称为数据竞争,示例如下:
import threading
sum = 0
tmp = 0
引入模块 threading
设定全局变量 sum 和 tmp 的初值为 0,它们被线程共享访问
def thread_entry():
global sum, tmp
for i in range(1000 * 1000):
tmp = sum + 1
sum = tmp
在第 1 行,定义线程入口 thread_entry
在第 2 行,声明共享变量 sum 和 tmp
在第 4 行,for 循环 1000* 1000 次,递增变量 sum
t0 = threading.Thread(target = thread_entry, args = ())
t1 = threading.Thread(target = thread_entry, args = ())
t0.start()
t1.start()
t0.join()
t1.join()
print('sum =', sum)
创建线程 t0,线程入口为 thread_entry
线程 t0 对变量 sum 递增 1000 * 1000 次
创建线程 t1,线程入口为 thread_entry
线程 t1 对变量 sum 递增 1000 * 1000 次
等待两个线程结束后,打印 sum 的值
线程 t0 对变量 sum 递增 1000 * 1000 次
线程 t1 对变量 sum 递增 1000 * 1000 次
第一次运行程序,输出结果如下:
sum = 1464661
再次运行程序,输出结果如下:
sum = 1415592
线程 t0 和 t1 对 sum 各自递增 1000 * 1000 次,期望最终的 sum 为 2 * 1000 * 1000。然而,线程 t0 和 线程 t1 共享访问变量 sum 和 tmp,存在数据竞争,导致:
实际结果依赖于线程的执行顺序,每次执行程序的输出结果都不一样
实际结果和预期不一致
3. 使用 lock 防止数据竞争
可以使用 threading 模块的类 Lock 防止数据竞争,示例如下:
import threading
sum = 0
tmp = 0
def thread_entry():
global sum, tmp
for i in range(1000 * 1000):
lock.acquire() # 获取锁
tmp = sum + 1
sum = tmp
lock.release() # 释放锁
lock = threading.Lock() # 初始化锁
t0 = threading.Thread(target = thread_entry, args = ())
t1 = threading.Thread(target = thread_entry, args = ())
t0.start()
t1.start()
t0.join()
t1.join()
print('sum =', sum)
和上个小节的例子相比,增加了 3 行代码 (使用注释标记):
lock.acquire(),访问共享变量 sum 和 tmp 前,需要获取锁
lock.release(),访问共享变量 sum 和 tmp 后,需要释放锁
lock = thread.Lock(),初始化锁
第一次运行程序,输出结果如下:
sum = 200000
再次运行程序,输出结果如下:
sum = 200000
线程 t0 和 t1 对 sum 各自递增 1000 * 1000 次,期望最终的 sum 为 2 * 1000 * 1000。使用了 lock 防止了数据竞争:
每次执行程序的输出结果都是相同的
实际结果和期望结果相符合
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)