Python线程与锁操作全局变量行为不符,问题出在哪里?
线程并发时print输出重复值的问题排查
我编写了如下Python代码:
from threading import Thread, Lock from time import sleep # 原代码漏了该导入,先补上 i = 1 lock = Lock() def t_func(): global i while True: lock.acquire() local_i = i i += 1 lock.release() sleep(1) print(i)
预期每个线程始终输出唯一的i值,但运行30个并发线程时出现如下重复输出:
743743 744 745 747 748 749 750 751 752 753 754754 755 757 758
请问我哪里出错了?
问题根源
你的锁只保护了i的递增操作,但完全没管print输出的过程。
多个线程完成i +=1后,会一起进入sleep(1),随后几乎同时触发print(i)。而Python的print函数本身不是线程安全的——它输出字符串到控制台的过程可能被其他线程打断,导致多个线程的输出内容直接叠加,看起来就像重复的数值。比如线程A刚输出"743"还没换行,线程B就输出了另一个"743",最终就出现了"743743"的错乱结果。
另外,原代码漏导入了sleep函数,但这不是输出重复的直接原因。
修复方案
把print操作也放到锁的保护范围内,确保每个线程的输出过程是原子性的:
方案1(推荐,逻辑更合理)
直接在锁内输出线程拿到的原始值,避免后续i被其他线程修改导致的输出偏差:
from threading import Thread, Lock from time import sleep i = 1 lock = Lock() def t_func(): global i while True: lock.acquire() local_i = i i += 1 print(local_i) # 输出线程自己拿到的唯一值 lock.release() sleep(1)
方案2(保留sleep后输出的逻辑)
如果一定要在sleep后输出,那输出时也要加锁:
from threading import Thread, Lock from time import sleep i = 1 lock = Lock() def t_func(): global i while True: # 先加锁拿到当前值并递增 lock.acquire() current_i = i i += 1 lock.release() sleep(1) # 输出时再次加锁,确保输出不被打断 lock.acquire() print(current_i) lock.release()
补充说明
原代码里print(i)输出的是递增后的i值,而不是线程自己拿到的local_i——比如线程A拿到local_i=743,i变成744;线程B接着拿到local_i=744,i变成745。两个线程sleep后都会输出745,这本身就会导致重复值。所以输出local_i才是符合"每个线程输出唯一值"预期的做法。
内容的提问来源于stack exchange,提问作者user16732580
相关产品推荐
相关产品推荐

