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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:45:33