49.Python进阶_队列01_先进先出队列

Python提供线程安全的FIFO队列,初始化时可设置最大消息数量。队列满时插入数据会阻塞,空时取出数据也会阻塞。常用方法包括q.full()、q.empty()和q.qsize()。join()方法会阻塞,直到队列中的所有任务被处理,task_done()用于标记任务已完成。正确使用task_done()与put的次数匹配才能避免阻塞。

Python的Quene模块中提供了同步的,线程安全的队列类,包括 -

  • FIFO(先进先出)队列Queue,
  • LIFO(先进后出)队列LifoQueue,
  • 优先级队列PriorityQueue

这些队列都实现了锁原语,能够在多线程中直接使用,可以使用列表来实现线程间同步;

初始化Queue()对象时,如果(q=Queue(),若括号中没有指定最大可接受的消息数量,或者数量为负值,那么代表可接受的消息数量没有上限)

队列的方法:

   put(self,item,block=True,time=None)     #给队列中添加数据
  get(self,block=True,timeout=None)     #从队列中获取数据
  • 如果队列满了,默认一直等待,
  1. timeout时间设置等待时间,后超过时间会报错,
  2. block设置为False就会不等待;和put_nowait方法一样

并且超过设置数量或者取出数量后都会报错;

基本FIFO队列(先进先出)

FIFO即First in First Out,先进先出。Queue提供了一个基本的FIFO容器,使用方法很简单,maxsize是个整数,指明了队列中能存放的数据个数的上限。一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉。如果maxsize小于或者等于0,队列大小没有限制。

from queue import Queue

q = Queue(5)  #创建队列对象

for i in range(5):

    q.put(i)  #给队列中添加数据

while not q.empty(): #判断是否为空
    print(q.get())#从队列中取出数据

运行结果:

0
1
2
3
4

如果队列中数据已满,继续添加数据会报错,同样如果已空,继续取数据也会报错;

from queue import Queue
q = Queue(4)  #创建队列对象

for i in range(5):
    q.put(i,block=False)  #给队列中添加数据和q.no_wait类似

运行结果:

  Traceback (most recent call last):
      File "E:/workspace/python/pythonDemo/0911/queueDemo.py", line 6, in <module>
        q.put(i,block=False)  #给队列中添加数据
      File "D:\softwore\Python\lib\queue.py", line 136, in put
        raise Full
    queue.Full
常用方法:
  • q.full() 判断是否已满
  • q.empty() #判断是否为空
  • q.qsize() #输出元素个数
from queue import Queue

q = LifoQueue(5)  #创建队列对象

for i in range(5):
    q.put(i,block=False)  #给队列中添加数据

print(q.full())  #判断队列是否已满
print('队列中元素个数为:',q.qsize())

while not q.empty(): #判断是否为空
    print(q.get())#从队列中取出数据


print(q.empty()) #判断队列是否为空
print('队列中元素个数为:',q.qsize())

join()方法和task_done()

阻塞调用线程,直到队列中的所有任务被处理掉。.join() 实际上意味着等到队列为空,再执行别的操作,没有执行task_done(),则join无法判断队列到底有没有结束,在最后执行个join()是等不到结果的,会一直挂起。
只要有数据被加入队列,未完成的任务数就会增加。当消费者线程调用task_done()(意味着有消费者取得任务并完成任务),未完成的任务数就会减少。当未完成的任务数降到0,join()解除阻塞。从而执行主线程。

from queue import Queue
q = Queue(5)
q.put(1)
q.put(2)
q.put(3)
q.put(4)
print('------4-------')
q.put(5)
print('-----5------')

q.put(6)
print('-----6------')

运行结果:

------4-------
-----5------

原本超出设定的队列满了之后会一直等待,停滞后面的都不会运行;

 from queue import Queue
    q = Queue(5)
    q.put(1)
    q.put(2)
    q.put(3)
    q.put(4)
    print('------4-------')
    
    #等待队列中的任务执行完,没有告诉它,会一直认为没执行完
    q.join()
    
    q.put(5)
    print('-----5------')
    
    q.put(6,block=True)
    print('-----6------')

运行结果:

------4-------

发现后面的并未执行;因为此刻的以为没有执行完,所以会一直等待,直到tesk_done告诉它已经执行完毕才可以;

from queue import Queue
q = Queue(5)
q.put(1)
q.put(2)
q.put(3)
#q.put(4)
print('------4-------')
q.task_done()
q.task_done()
q.task_done()
#q.task_done()
#等待队列中的任务执行完,没有告诉它,会一直认为没执行完
q.join()

q.put(5)
print('-----5------')

q.put(6,block=True)
print('-----6------')

运行结果:

------4-------
-----5------
-----6------

上面需要使用q.task_done()来声明任务已执行完,但是只加一个是不行的,之前给队列中添加了几个数据也就是使用了几次put,就需要使用几次task_done(),使用多了会报错;

""" 文本转语音引擎(TTS) ✅ 使用事件回调机制通知播放状态 ✅ 支持外部注册 on_start / on_stop 回调 ✅ 队列驱动 + 线程安全 + 可停止 """ import threading import queue import time from typing import Optional, Callable, List from Progress.utils.logger_config import setup_logger logger = setup_logger("tts_engine") # 定义回调类型 PlaybackCallback = Callable[[], None] class TextToSpeechEngine: def __init__(self): self._tts_queue = queue.Queue() self._stop_event = threading.Event() self._worker_thread: Optional[threading.Thread] = None self._is_playing = False self._lock = threading.Lock() # 保护 _is_playing 和回调列表 # 播放生命周期回调函数列表 self._on_start_callbacks: List[PlaybackCallback] = [] self._on_stop_callbacks: List[PlaybackCallback] = [] def start(self): """启动 TTS 引擎工作线程""" if self._worker_thread is None: self._worker_thread = threading.Thread(target=self._playback_worker, daemon=True) self._worker_thread.start() logger.info("🎧 TTS 引擎已启动") def stop(self): """优雅关闭 TTS 引擎""" self._stop_event.set() self._tts_queue.put(None) # 唤醒阻塞中的 get() if self._worker_thread: self._worker_thread.join(timeout=2) logger.info("🛑 TTS 引擎已停止") def register_playback_callback(self, on_start: Optional[PlaybackCallback] = None, on_stop: Optional[PlaybackCallback] = None): """ 注册播放事件回调(用于联动语音识别等模块) :param on_start: TTS 开始播放时调用 :param on_stop: TTS 播放结束后调用 """ with self._lock: if on_start: self._on_start_callbacks.append(on_start) if on_stop: self._on_stop_callbacks.append(on_stop) logger.debug("✅ 注册 TTS 播放回调函数") def _notify_start(self): """通知所有监听者:TTS 开始了""" with self._lock: callbacks = self._on_start_callbacks.copy() for cb in callbacks: try: cb() except Exception as e: logger.warning(f"⚠️ TTS on_start 回调异常: {e}") def _notify_stop(self): """通知所有监听者:TTS 结束了""" with self._lock: callbacks = self._on_stop_callbacks.copy() for cb in callbacks: try: cb() except Exception as e: logger.warning(f"⚠️ TTS on_stop 回调异常: {e}") @property def is_playing(self) -> bool: with self._lock: return self._is_playing def speak(self, text: str, block: bool = False): """ 提交一段文本进行语音播报 :param text: 要朗读的文本 :param block: 是否阻塞直到播放完成 """ if not text.strip(): logger.debug("🟡 忽略空文本") return # ❌ 如果正在播放,直接跳过(可改为排队或打断策略) acquired = self._lock.acquire(timeout=0.1) if not acquired: logger.warning("🔒 无法获取锁,跳过 TTS") return try: if self._is_playing: logger.warning("🎙️ TTS 正在播放,跳过: %s", text[:50]) return self._is_playing = True finally: self._lock.release() # ✅ 触发开始事件(必须在加锁后、入队前) self._notify_start() logger.info("📢 推送 TTS 文本: %s", text) self._tts_queue.put(text) # 🔒 同步等待播放完成(可选) if block: while self.is_playing and not self._stop_event.is_set(): time.sleep(0.1) return text def _synthesize_and_play_audio(self, text: str): """ 执行实际的语音合成与播放 ✅ 可替换为 pyttsx3 / edge-tts / vosk-tts / sox 等 """ try: # 示例:使用本地 pyttsx3(离线可用) import pyttsx3 engine = pyttsx3.init() # 可配置语速、音量、语音 rate = engine.getProperty('rate') engine.setProperty('rate', rate - 50) # 稍慢一点更自然 voices = engine.getProperty('voices') for v in voices: if "zh" in v.languages or "Chinese" in v.name: engine.setProperty('voice', v.id) break engine.say(text) engine.runAndWait() # 同步阻塞直到播放完成 except ImportError: logger.error("❌ 缺少 pyttsx3,请安装: pip install pyttsx3") raise except Exception as e: logger.error("❌ TTS 播放异常: %s", e) raise def _playback_worker(self): """后台播放线程:从队列中取出任务并执行""" logger.debug("🧵 TTS 工作线程已启动") while not self._stop_event.is_set(): try: text = self._tts_queue.get(timeout=1) if text is None: # 停止信号 break try: logger.info("🔊 开始播放 TTS: %s", text[:60]) self._synthesize_and_play_audio(text) logger.info("✅ TTS 播放完成") except Exception as e: logger.error("💥 播放失败: %s", e) finally: # ✅ 播放结束 → 更新状态 + 通知停止 with self._lock: self._is_playing = False self._notify_stop() # 👈 在 finally 外也确保通知 self._tts_queue.task_done() except queue.Empty: continue except Exception as e: logger.exception("🚨 TTS 工作线程发生未预期错误: %s", e) with self._lock: self._is_playing = False self._notify_stop() logger.info("⏹️ TTS 工作线程退出") 还有这个
最新发布
10-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值