You need to enable JavaScript to run this app. 为什么Python守护线程内的while True循环会阻塞主代码执行?
优惠活动
大模型
产品
解决方案
定价
更多

为什么Python守护线程内的while True循环会阻塞主代码执行?

阻塞问题核心成因
  • 最根本的启动逻辑错误:完全没有真正启动子线程
    在自定义Mysql类的__init__方法末尾,直接写入了self.run()调用。这是普通实例方法的同步执行,整个过程都跑在主线程的执行栈上,没有触发Python threading模块的新线程创建流程。
    threading.Thread类的正确启动方式是调用实例的.start()方法:这个方法才会和操作系统交互创建独立执行流,让后台新线程去执行run()中定义的逻辑。直接调用run()的写法和调用普通成员方法没有任何区别,while True循环会直接把主线程卡死在该方法内部,代码永远走不到data = Mysql()之后的逻辑,这就是“程序无法越过循环继续执行”的直接原因。
  • 已设置的daemon守护线程属性完全失效
    守护线程的标记仅对被.start()方法拉起的独立系统线程生效,当前所有代码都运行在主线程中,该属性不会对实际执行流产生任何作用。
  • 即使修正了启动方式,现有代码还存在两处会导致运行异常的隐患:
    • 共享同一MySQL游标mycursor的线程安全问题:mysql-connector-python的游标对象并非线程安全,多个线程同时调用同一个游标执行查询,会出现游标状态错乱、返回结果不匹配、甚至数据库连接被强制断开的问题。正确做法是为每个线程创建独立的数据库连接和游标,或为所有数据库操作加全局互斥锁。
    • 无休眠的忙循环消耗资源:while True数据库读取循环没有加入任何休眠逻辑,会将单个CPU核心占满,无意义地消耗系统资源,应在每轮循环后加入短休眠(如0.1秒),降低数据库查询频率。
修正后的核心逻辑参考
class Mysql(threading.Thread):
    def __init__(self):
        super().__init__()
        self.daemon = True
        self.en = 1
        self.læsTidScoreNu = "SELECT tidSCoreNu FROM bois WHERE id = 1"
        self.læsTidMål = "SELECT tidMål FROM bois WHERE id = 1"
        self.opdaterTidMål = "UPDATE bois SET tidMål = %s WHERE id = %s"
        self.læsStopKnap = "SELECT stopKnap FROM bois WHERE id = 1"
        # 为子线程创建独立数据库连接,避免和主线程共享游标
        self.thread_db = mysql.connector.connect(
            host="",
            user="",
            password="",
            database='',
            auth_plugin=''
        )
        self.thread_cursor = self.thread_db.cursor(prepared=True)

    def run(self) -> None:
        # 先执行一轮查询,给状态变量赋初始值,避免主线程首次读取时出现属性不存在的错误
        self.thread_cursor.execute(self.læsTidScoreNu)
        self.råTidScoreNu = self.thread_cursor.fetchone()
        self.tidScoreNu = float("{}".format('%.2f' % self.råTidScoreNu))
        self.thread_cursor.execute(self.læsTidMål)
        self.råTidMål = self.thread_cursor.fetchone()
        self.tidMål = float("{}".format('%.2f' % self.råTidMål))
        self.thread_cursor.execute(self.læsStopKnap)
        self.stopKnap = self.thread_cursor.fetchone()[0]

        while True:
            self.thread_cursor.execute(self.læsTidScoreNu)
            self.råTidScoreNu = self.thread_cursor.fetchone()
            self.tidScoreNu = float("{}".format('%.2f' % self.råTidScoreNu))
            self.thread_cursor.execute(self.læsTidMål)
            self.råTidMål = self.thread_cursor.fetchone()
            self.tidMål = float("{}".format('%.2f' % self.råTidMål))
            self.thread_cursor.execute(self.læsStopKnap)
            self.stopKnap = self.thread_cursor.fetchone()[0]
            # 短休眠降低CPU占用
            sleep(0.1)

# 正确启动线程:调用start(),而非直接调用run()
data = Mysql()
data.start()
# 等待子线程完成首轮初始化赋值,避免主线程读取到未初始化的变量
sleep(0.5)

额外注意:原代码中读取stopKnap时,fetchone()返回的是元组类型,直接拿元组和整数1做判断永远不会成立,需要取元组的第一个元素再做比较。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.13 06:54:02