欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > threading.Lock()凡是多线程中涉及“写操作”的变量、文件、列表,一定要加锁保护,避免多个线程抢着改

threading.Lock()凡是多线程中涉及“写操作”的变量、文件、列表,一定要加锁保护,避免多个线程抢着改

2025/4/19 11:38:27 来源:https://blog.csdn.net/u013565133/article/details/147218057  浏览:    关键词:threading.Lock()凡是多线程中涉及“写操作”的变量、文件、列表,一定要加锁保护,避免多个线程抢着改

🧠 什么是共享写操作?

假设有多个线程同时访问一个变量、列表、文件,并且都在 “修改”它,这就是“共享写操作”。

比如:

my_list = []def worker():for i in range(1000):my_list.append(i)

如果多个线程同时运行 worker(),就会同时往 my_list 里加数据,结果就可能丢数据、重复数据,因为:

Python 在执行 append 的时候被另一个线程打断了,就会导致写错!


✅ 怎么加锁?

用 Python 的 threading.Lock(),可以防止多个线程同时进入“关键区”。


🔒 正确的加锁方式如下:

import threadinglock = threading.Lock()  # 创建一把锁my_list = []def worker():for i in range(1000):with lock:                # 加锁my_list.append(i)     # 关键操作

关键语法是:

with lock:# 这里是临界区(共享资源修改)

🔐 这段代码的含义是:

  • 每次有线程要操作共享资源时,先**“申请钥匙”**
  • 如果锁已经被别的线程拿了,就等着
  • 拿到锁后,线程可以安全修改数据,改完会自动释放锁

这段代码:

with results_lock:results.append(item)

就代表:

  • 多个线程都要往 results 这个共享列表中 append
  • 所以必须加锁,用 results_lock 包起来,防止冲突
  • 不加锁可能会导致:部分数据没加进去、程序报错、数据错乱

🧪 真实例子演示(无锁 vs 有锁)

import threadingcount = 0
lock = threading.Lock()def add():global countfor _ in range(100000):with lock:count += 1threads = []
for _ in range(5):t = threading.Thread(target=add)t.start()threads.append(t)for t in threads:t.join()print("最终结果:", count)

如果不加锁,会发现 count 的结果可能会小于 500000!


我们再以一个“银行账户”的例子来模拟真实问题:


🧪 场景模拟:多个线程给一个银行账户转账,每次加 1 块钱,转 10 万次

我们用两个版本来比较:


✅ 有加锁的版本(正确做法)

import threadingbalance = 0  # 银行账户初始余额
lock = threading.Lock()def deposit():global balancefor _ in range(100000):  # 每个线程转账 10 万次,每次 1 元with lock:balance += 1threads = []
for _ in range(5):  # 启动 5 个线程一起转账t = threading.Thread(target=deposit)t.start()threads.append(t)for t in threads:t.join()print("✅加锁后最终余额:", balance)  # 期望结果:500000
📌 输出示例:
✅加锁后最终余额: 500000

❌ 不加锁的版本(容易出问题)

import threadingbalance = 0  # 初始余额def deposit():global balancefor _ in range(100000):balance += 1  # ❌ 多线程同时写,容易数据冲突threads = []
for _ in range(5):  # 启动 5 个线程t = threading.Thread(target=deposit)t.start()threads.append(t)for t in threads:t.join()print("❌未加锁最终余额:", balance)  # 理想应该是 500000,实际可能是 47xxxx
📌 输出示例:
❌未加锁最终余额: 473861

🧠 为什么不加锁就会出错?

这是因为:

balance += 1

其实包含三个步骤:

  1. 从内存中读取 balance
  2. 计算 balance + 1
  3. 写回内存

多个线程同时执行时,可能都读到了旧值,然后计算后覆盖写入,导致有的“+1”被覆盖了!


📊 可视化比喻:

想象你和你朋友一起在一张纸上记录余额,你俩同时看到余额是 100:

  • 你算完后写 101
  • 朋友也算完后写 101

最后纸上的余额还是 101,本来应该是 102,这就是数据丢失!


✅ 最佳实践总结

场景是否需要加锁
多线程修改共享变量(如列表、字典、计数器)✅ 必须加锁
多线程只读取共享变量❌ 不需要加锁
多线程读写文件✅ 加锁写操作
每个线程操作独立变量❌ 不需要加锁

✅ 总结一句话:

凡是多线程中涉及“写操作”的变量、文件、列表,一定要加锁保护,避免多个线程抢着改。

只读不写的就不用加锁,比如读取文件、只看数据等。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词