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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 21:18:23