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

Python多线程缩进问题:IF语句缩进改变线程执行结果

解决Python多线程队列同步问题:仅单个线程执行任务的原因及修复方案

看起来你遇到的问题是因为手动加锁逻辑和线程调度的交互冲突,再加上教程里的代码可能存在排版误导(甚至语法错误),才出现了这种奇怪的现象。让我一步步帮你理清:

问题根源分析

你当前的代码存在两个核心问题:

  1. 不必要的手动锁打乱了同步逻辑:queue.Queue本身就是线程安全的,它的get()和put()方法已经内置了同步机制,完全不需要你手动加queueLock。你现在的手动锁反而干扰了线程间的正常调度——当多个线程竞争锁时,某个线程可能会反复获取锁并处理所有任务,其他线程则因为锁竞争失败或队列提前为空而直接退出。
  2. 线程启动与队列填充的时机问题:你先启动线程再填充队列,线程启动后立刻进入循环,此时队列为空,它们会释放锁并sleep(1)。当主线程填充完队列后,最先醒来的线程(比如Thread-3)会持续抢占锁处理数据,等其他线程醒来时队列已经空了,紧接着exitFlag被设置为1,这些线程就直接退出了。

另外你提到教程里的if语句是缩进的——这其实是语法错误,Python不允许无意义的深层缩进,PyCharm提示“缩进多余”是完全正确的,那种缩进的代码根本无法正常运行,大概率是教程排版出了问题。

修正后的代码

去掉多余的手动锁,利用queue.Queue本身的线程安全特性处理同步,代码会简洁且可靠得多:

import queue
import threading
import time

exitFlag = 0

class myThread (threading.Thread):
    def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q
    def run(self):
        print(f"Starting {self.name}")
        process_data(self.name, self.q)
        print(f"Exiting {self.name}")

def process_data(threadName, q):
    while not exitFlag:
        try:
            # get()方法会阻塞直到有数据,timeout=1用于定期检查exitFlag
            data = q.get(timeout=1)
            print(f"{threadName} processing {data}")
            q.task_done()  # 标记当前任务完成
        except queue.Empty:
            # 队列为空时继续循环,检查exitFlag状态
            continue

threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
workQueue = queue.Queue(10)
threads = []
threadID = 1

# 先填充队列再启动线程(也可以先启动线程,不影响,但先填充更直观)
for word in nameList:
    workQueue.put(word)

# 创建并启动线程
for tName in threadList:
    thread = myThread(threadID, tName, workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1

# 等待队列中所有任务处理完成
workQueue.join()

# 通知线程可以退出
exitFlag = 1

# 等待所有线程结束
for t in threads:
    t.join()

print("Exiting Main Thread")

关键改进点

  • 移除手动锁:依赖queue.Queue内置的同步机制,避免手动锁带来的调度混乱。
  • 使用q.get(timeout=1):让线程在队列为空时不会无限阻塞,而是定期检查exitFlag,确保能及时响应退出信号。
  • 添加q.task_done()和workQueue.join():更可靠地等待所有队列任务处理完成,替代原来的while not workQueue.empty()轮询方式。
  • 调整队列填充时机:先填充队列再启动线程,让线程启动后就能立刻处理数据,避免初始的空队列等待。

这样修改后,三个线程会均匀竞争队列中的任务,不会出现只有单个线程干活的情况了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:25:04