Python线程同步原语必要性验证:寻求竞态条件差异示例
多线程同步原语的差异示例
为什么你的初始代码没出现竞态
你之前的代码未触发竞态,是因为CPython的全局解释器锁(GIL)在执行简单字节码序列时不会频繁释放。counter += 1虽拆分为读取、计算、赋值三个非原子步骤,但如果线程在执行这几步时未被GIL调度打断,结果就会符合预期。要明显展示竞态,需让线程在修改共享变量时更易被切换。
无锁与加锁的对比示例
以下示例通过拆分递增操作并加入微小延迟,刻意触发线程切换,清晰展示同步原语的作用:
无锁版本(存在竞态)
from threading import Thread import time COUNT = 1000 NUM_THREADS = 10 counter = 0 def increment(): global counter for _ in range(COUNT): # 显式拆分递增步骤,加入微小延迟触发GIL释放 current = counter time.sleep(0.000001) counter = current + 1 threads = [Thread(target=increment) for _ in range(NUM_THREADS)] for thread in threads: thread.start() for thread in threads: thread.join() print(f"无锁结果: {counter}") print(f"预期结果: {COUNT * NUM_THREADS}") print(f"差值: {counter - COUNT * NUM_THREADS}")
运行后,counter的值会远小于预期的10000——多个线程会同时读取到相同的current值,各自加1后赋值,导致大量递增操作被覆盖。
加锁版本(无竞态)
from threading import Thread, Lock import time COUNT = 1000 NUM_THREADS = 10 counter = 0 lock = Lock() def increment(): global counter for _ in range(COUNT): # 使用Lock确保临界区代码原子执行 with lock: current = counter time.sleep(0.000001) counter = current + 1 threads = [Thread(target=increment) for _ in range(NUM_THREADS)] for thread in threads: thread.start() for thread in threads: thread.join() print(f"加锁结果: {counter}") print(f"预期结果: {COUNT * NUM_THREADS}") print(f"差值: {counter - COUNT * NUM_THREADS}")
运行后,counter的值会严格等于10000——with lock块保证同一时间只有一个线程能执行临界区代码,彻底避免了数据竞争。
内容的提问来源于stack exchange,提问作者ibarbylev
相关产品推荐
相关产品推荐

