Python线程在while循环首次input时冻结问题求助
问题分析与解决方案
核心错误:队列引用错误
你的代码存在一个致命的低级错误:主循环中你试图往**函数对象read_queue**里添加元素,而非目标队列play_queue。代码里的read_queue.append(song)必须改为play_queue.append(song)。
这个错误直接导致第一次输入的音频路径根本没进入播放队列,播放线程一直在空循环打印"Empty queue"。当你第二次输入时,虽然错误仍存在,但主程序的input阻塞被打破,后续流程因Python函数对象可动态添加属性的特性进入看似正常的状态,但这完全不符合预期逻辑。
线程安全问题
普通列表play_queue的append和pop(0)操作并非线程安全,多线程环境下可能引发数据竞争。建议使用Python标准库的queue.Queue,它原生支持线程安全操作,还自带阻塞等待功能,能大幅简化播放线程的逻辑。
修正后的完整代码
import threading import time import soundfile as sf import sounddevice as sd from queue import Queue # 替换为线程安全的Queue play_queue = Queue() SPEAKERS_ID = 0 # 请根据你的实际音频设备ID修改 def read_queue(): while True: # Queue.get()会自动阻塞,直到队列有元素,无需手动判断空队列 print("Getting file...") file = play_queue.get() print("Calling play function...") play(file, SPEAKERS_ID) print("Removing from queue...") play_queue.task_done() # 标记任务完成,规范写法 def play(filename, device_id): print("Starting play function...") try: print("Reading file") data, fs = sf.read(filename, dtype='float32') print("File read") print("Playing audio...") sd.play(data, fs, device=device_id) sd.wait() print("Fin del audio.") except Exception as e: print(f"Un error desconocido ha ocurrido: {e}") if __name__ == '__main__': threading.Thread(target=read_queue, daemon=True).start() song = input("Prompt: ") while song.lower() != 'exit': # 修正队列引用,使用线程安全的put方法 play_queue.put(song) song = input("Prompt: ")
额外优化点
- 使用
queue.Queue的get()方法自动阻塞等待队列元素,省去手动sleep和空队列判断的代码,逻辑更简洁高效。 play_queue.task_done()可配合join()方法(若需等待队列所有任务完成再退出程序),当前用daemon线程可省略,但加上更规范。- 确保
SPEAKERS_ID设置为实际音频输出设备ID,可通过sd.query_devices()命令查看设备列表。
内容的提问来源于stack exchange,提问作者Benjas333
相关产品推荐
相关产品推荐

