You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python threading.Lock未按互斥锁预期工作,求技术解答

问题

我一直认为threading.Lock对象可作为互斥锁(mutex),用于避免Python多线程脚本中的竞态条件,但实际测试后发现两种可能:1. 我的认知错误(与多年经验相悖);2. Python 2.7-3.9版本存在相关Bug。理论上,只要用Lock保护临界区(即执行值增量的代码),多线程共享值的增量操作就不会有问题,但运行以下代码后,发现互斥锁未达到预期效果,恳请各位解惑:

#!/usr/bin/env python

from __future__ import print_function
import sys
import threading
import time

Stop = False

class T(threading.Thread):

  def __init__(self,list_with_int):
    self.mycount = 0
    self.to_increment = list_with_int
    super(T,self).__init__()

  def run(self,):
    while not Stop:
      with threading.Lock():
        self.to_increment[0] += 1
      self.mycount += 1

intList = [0]
t1 = T(intList)
t2 = T(intList)
t1.start()
t2.start()

Delay = float(sys.argv[1]) if sys.argv[1:] else 3.0

time.sleep(Delay)

Stop = True
t1.join()
t2.join()
total_internal_counts = t1.mycount + t2.mycount

print("Compare:\n\t{total_internal_counts}\n\t{intList[0]}\n".format(**locals()))

assert total_internal_counts == intList[0]
解答

问题出在你每次循环都新建了一个threading.Lock实例,两个线程用的根本不是同一个锁,自然起不到互斥作用。

原代码里with threading.Lock()这行,每次循环都会生成全新的锁对象,相当于两个线程各自拿自己的锁,完全没限制对方访问临界区,竞态条件当然会出现,导致intList[0]的数值比total_internal_counts小。

修复很简单:在主线程创建一个共享锁,传给两个线程,让它们用同一个锁保护临界区。修改后的代码如下:

#!/usr/bin/env python

from __future__ import print_function
import sys
import threading
import time

Stop = False

class T(threading.Thread):

  def __init__(self, list_with_int, lock):
    self.mycount = 0
    self.to_increment = list_with_int
    self.lock = lock  # 保存共享锁
    super(T, self).__init__()

  def run(self):
    while not Stop:
      with self.lock:  # 使用共享锁
        self.to_increment[0] += 1
      self.mycount += 1

intList = [0]
shared_lock = threading.Lock()  # 创建共享锁实例
t1 = T(intList, shared_lock)
t2 = T(intList, shared_lock)
t1.start()
t2.start()

Delay = float(sys.argv[1]) if sys.argv[1:] else 3.0

time.sleep(Delay)

Stop = True
t1.join()
t2.join()
total_internal_counts = t1.mycount + t2.mycount

print("Compare:\n\t{total_internal_counts}\n\t{intList[0]}\n".format(**locals()))

assert total_internal_counts == intList[0]

修改后,两个线程会争抢同一个锁,临界区的增量操作被正确保护,intList[0]和total_internal_counts会始终相等,断言不会触发。

另外说明:Python 2.7到3.9版本的threading.Lock本身没有这类功能Bug,问题完全是代码实现错误,和版本无关。

内容的提问来源于stack exchange,提问作者Daniel Moore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 16:30:45