Python不同数据类型成员变量在同优先级线程中更新不同步问题
问题原因分析
- 线程调度的不确定性:Python的全局解释器锁(GIL)会在字节码执行间隙切换线程。虽然主线程先调用
changeString()再调用changeBool(),但这两个操作执行速度极快,可能在新线程还没进入循环检测阶段时,主线程就已经完成了两个变量的修改。当新线程开始检测时,self.bool已经为True,自然会优先触发对应分支。 - 变量可见性问题:Python普通成员变量没有内存屏障或同步机制,新线程可能会缓存
self.string的初始空值,无法及时感知主线程的修改。而bool类型操作更简单,缓存刷新的时机更容易让线程检测到变化,最终导致每次都先输出"Bool changed"。
解决方法
要确保变量修改后立即被其他线程感知,可采用以下几种线程安全的实现方式:
方式一:使用threading.Lock保证同步与可见性
通过锁保护变量的读写操作,强制线程间的内存可见性:
import threading class Test: def __init__(self) -> None: self.bool = False self.string = "" self.lock = threading.Lock() thread = threading.Thread(target=self.target) thread.start() def target(self): while True: with self.lock: if self.bool: print("Bool changed") break if self.string != "": print("String changed") break def changeBool(self): with self.lock: self.bool = True def changeString(self): with self.lock: self.string = "sample" var = Test() var.changeString() var.changeBool()
方式二:使用threading.Event精准标记状态
用事件对象标记变量修改状态,避免轮询带来的不确定性:
import threading class Test: def __init__(self) -> None: self.string_event = threading.Event() self.bool_event = threading.Event() thread = threading.Thread(target=self.target) thread.start() def target(self): # 等待任意一个事件触发 triggered = threading.wait([self.string_event, self.bool_event]) if triggered == self.string_event: print("String changed") else: print("Bool changed") def changeBool(self): self.bool_event.set() def changeString(self): self.string_event.set() var = Test() var.changeString() var.changeBool()
方式三:使用queue传递修改通知
通过队列传递修改信息,天然保证线程安全和可见性:
import threading import queue class Test: def __init__(self) -> None: self.q = queue.Queue() thread = threading.Thread(target=self.target) thread.start() def target(self): msg = self.q.get() print(f"{msg} changed") def changeBool(self): self.q.put("Bool") def changeString(self): self.q.put("String") var = Test() var.changeString() var.changeBool()
内容的提问来源于stack exchange,提问作者Anchith Acharya
相关产品推荐
相关产品推荐

