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

Python Threading疑问:无阻塞逻辑下Consumer为何先于Producer执行?

问题分析与解答

首先,你遇到的线程执行顺序、Consumer未处理全部元素的问题,核心原因有两个:操作系统的线程调度机制,以及Consumer遍历列表的逻辑缺陷。

1. 线程启动≠立即执行

你调用t.start()只是把线程加入操作系统的就绪队列,至于哪个线程先获得CPU时间片执行,完全由操作系统的调度器决定,和你启动线程的顺序无关。比如你先启动Producer线程,操作系统可能先让它跑几个循环,再切换到Consumer线程;也有可能反过来,让Consumer先跑(此时data为空,Consumer的循环直接结束,什么都不打印)。你当前的输出里Producer先输出0-3,只是调度器这次选择了先让Producer执行一段时间。

2. Consumer的遍历逻辑不监听新元素

你的Consumer线程里用for i in data遍历列表,这个循环会在开始执行时生成一个列表的迭代器,迭代器只会遍历当时列表中已有的元素。也就是说:

  • 如果Producer先往data里加了0、1、2、3这四个元素,此时Consumer开始循环,就只会遍历这四个元素;
  • 之后Producer再追加第4个元素时,Consumer的循环已经结束了,所以不会处理这个元素——这也是你输出里producer 4在Consumer输出之后的原因。

3. 程序的核心问题:缺乏线程同步

因为没有任何同步机制(比如锁、条件变量),Producer和Consumer完全独立执行,会导致:

  • Consumer可能在data为空时就开始遍历,什么都不输出;
  • Consumer无法处理Producer在它开始遍历之后追加的新元素;
  • 虽然Python列表的append方法是线程安全的,但如果有更复杂的操作(比如弹出元素),会出现竞态条件。

改进后的示例代码

如果想让Consumer能依次处理Producer生成的所有元素,可以用threading.Condition实现标准的生产者-消费者同步:

import threading
import datetime
from colorama import Fore as colorify

def main() -> None:
    data = []
    condition = threading.Condition()

    threads = [
        threading.Thread(target=producer, args=(data, 5, condition), daemon=True),
        threading.Thread(target=consumer, args=(data, 5, condition), daemon=True)
    ]

    [t.start() for t in threads]
    [t.join() for t in threads]

    print(f"{colorify.YELLOW}Execution completed")

def producer(data: list, num: int, condition: threading.Condition) -> None:
    for i in range(num):
        _t = datetime.datetime.now()
        sqrt = i * i
        with condition:
            data.append([i, _t])
            print(f"{colorify.BLUE} producer {i} {threading.get_ident()}")
            condition.notify()  # 通知Consumer有新数据可用

def consumer(data: list, num: int, condition: threading.Condition) -> None:
    count = 0
    while count < num:
        with condition:
            # 等待直到data中有新元素
            while not data:
                condition.wait()
            item = data.pop(0)
            count += 1
        number = item[0]
        _t = item[1]
        print(f"{colorify.RED} consumer {number}  {threading.get_ident()}")

if __name__ == "__main__":
    main()

这个改进版本的特点:

  • 用Condition实现线程间的同步通知,Producer生产数据后唤醒等待的Consumer;
  • Consumer会一直等待直到有数据可用,保证每个生产的元素都被消费;
  • 避免了竞态条件,执行顺序更符合生产者-消费者的预期逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 21:01:00