Python控制台音乐播放器并行计算:歌曲结束后计时器无法终止
问题根因
你的代码里计时器线程无法自动终止,核心是三个逻辑错误:
- 传给
timer线程的参数是不可变字符串类型,线程启动时会拿到参数值的独立副本,后续主线程里res变量修改为"end"时,计时器线程内的判断变量完全感知不到变化,while x != "end"的判断永远成立,线程会无限循环。 - 没有给计时线程设置守护属性,且主循环每轮都会新启动一个计时线程,运行时间久了后台会堆积大量无效计时线程,占用资源。
- 计时器初始时间戳写死为
73800,每次启动都从固定时间点开始计时,不符合播放器从0开始统计播放时长的预期。
修复方案
用线程安全的threading.Event作为跨线程的播放终止标记,替换原来传字符串判断的逻辑,同时修正计时逻辑、线程属性,修复后完整代码如下:
import playsound import threading import time import sys def timer(stop_event): play_seconds = 0 while not stop_event.is_set(): # 直接将播放秒数格式化为时分秒,避免时区和固定初始值问题 hours = play_seconds // 3600 minutes = (play_seconds % 3600) // 60 seconds = play_seconds % 60 print(f"\r{hours:02d}:{minutes:02d}:{seconds:02d}", end="") time.sleep(1) play_seconds += 1 print("\r播放结束") def player(filename, stop_event): print(f"Playing: {filename}") playsound.playsound(filename) # 播放完成触发停止信号 stop_event.set() return "end" def main(): input_name = input("Please enter a file name: ") # 初始化线程安全的停止标记 stop_flag = threading.Event() # 启动守护线程,主线程退出时自动回收 timer_thread = threading.Thread(target=timer, args=(stop_flag,), daemon=True) timer_thread.start() play_res = player(input_name, stop_flag) print(play_res) # 等计时线程正常退出 timer_thread.join() sys.exit(0) if __name__ == "__main__": main()
关键修改说明
- 用
threading.Event做跨线程终止信号:这是Python标准库提供的线程安全同步原语,主线程播放完成后调用set()方法,计时线程能立刻检测到状态变化,跳出循环自动终止,不存在参数拷贝导致的状态不同步问题。 - 计时逻辑重构:从0秒开始累加播放时长,直接计算时分秒格式化输出,解决了原来固定初始值、时区偏移导致的计时不准问题。
- 计时线程设置
daemon=True:标记为守护线程,就算播放过程中出现异常导致主线程退出,后台计时线程也会被自动回收,不会出现程序退不干净的问题。 - 去掉了原来主循环无限启动新线程的逻辑,单次播放只启动一个计时线程,播放结束后等待线程正常退出再终止程序,不会堆积无效后台线程。
内容的提问来源于stack exchange,提问作者Mohsen Rahmani
相关产品推荐
相关产品推荐

