Python threading.Thread:print()随机丢失末尾换行问题排查
关于Python线程中print输出换行异常的问题
我正在学习Python threading模块,编写了如下代码以理解线程工作机制:
from time import sleep from threading import Thread closeAllThreads = False threadCounter = 0 def runMeAsThread(): global closeAllThreads, threadCounter threadCounter += 1 sleepValue = threadCounter while not closeAllThreads: print(f'runMeAsThread(): {threadCounter = } {sleepValue = }', flush=True) sleep(sleepValue) firstThreadObj = Thread(None,runMeAsThread) firstThreadObj.start() secondThreadObj = Thread(None,runMeAsThread) secondThreadObj.start() thirdThreadObj = Thread(None,runMeAsThread) thirdThreadObj.start() sleep(5) closeAllThreads = True
我预期所有打印内容都应单独占一行,但却随机出现两行内容打印在同一行的情况,示例如下:
runMeAsThread(): threadCounter = 1 sleepValue = 1 runMeAsThread(): threadCounter = 2 sleepValue = 2 runMeAsThread(): threadCounter = 3 sleepValue = 3 runMeAsThread(): threadCounter = 3 sleepValue = 1 runMeAsThread(): threadCounter = 3 sleepValue = 2runMeAsThread(): threadCounter = 3 sleepValue = 1 runMeAsThread(): threadCounter = 3 sleepValue = 3runMeAsThread(): threadCounter = 3 sleepValue = 1 runMeAsThread(): threadCounter = 3 sleepValue = 2 runMeAsThread(): threadCounter = 3 sleepValue = 1
我已为print()添加flush=True参数,但问题仍未解决,请问这是什么原因?是否还会出现打印内容混杂的情况?
问题原因
Python的print()函数默认会在末尾加换行符\n,但这个操作不是原子性的——它会分成两步执行:先输出字符串主体内容,再输出换行符。在多线程环境下,线程调度是随机的,可能出现线程A刚输出完字符串内容,还没来得及输出换行符,线程B就抢占CPU开始输出自己的字符串,最终导致两行内容挤在同一行。
你加的flush=True只是强制刷新输出缓冲区,让内容立刻显示出来,但并没有解决打印操作不原子的核心问题,所以异常依然会出现。
是否会出现更严重的内容混杂?
是的,极端场景下甚至会出现字符串内容互相穿插的情况(比如线程A输出一半字符串时,线程B插入输出自己的内容),你遇到的换行异常只是相对轻微的表现形式。
解决方法
要彻底解决这个问题,需要保证整个打印操作是原子性的,最常用的方案是使用线程锁(Lock):
from time import sleep from threading import Thread, Lock closeAllThreads = False threadCounter = 0 print_lock = Lock() # 创建一个全局线程锁 def runMeAsThread(): global closeAllThreads, threadCounter threadCounter += 1 sleepValue = threadCounter while not closeAllThreads: with print_lock: # 进入代码块时自动获取锁,退出时自动释放 print(f'runMeAsThread(): {threadCounter = } {sleepValue = }', flush=True) sleep(sleepValue) # 创建并启动线程 firstThreadObj = Thread(target=runMeAsThread) firstThreadObj.start() secondThreadObj = Thread(target=runMeAsThread) secondThreadObj.start() thirdThreadObj = Thread(target=runMeAsThread) thirdThreadObj.start() sleep(5) closeAllThreads = True
通过Lock的with语句,可以确保同一时间只有一个线程执行print操作,从根源上避免输出混乱。
内容的提问来源于stack exchange,提问作者user7711283
相关产品推荐
相关产品推荐

