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

如何在播放音频时让Python循环继续执行后续代码?

问题:音频播放阻塞循环,需实现后台播放同时迭代

我正在开发一款程序,功能为读取文本文件中的单词,当找到与音频文件名匹配的单词时播放对应的音频。目前遇到的问题是:for循环必须等待playsound()函数完成音频播放后才会继续迭代。我希望实现音频在后台播放的同时,循环能立即进入下一次迭代,请问该如何实现?

我的代码如下:

import os
from playsound import playsound
import time

text = open("book.txt",encoding="utf-8").read()
words_length = len(text.split())
split = text.split()
path = "Audio_tracks"
dir_list = os.listdir(path)

def linear_search(list, n , key):
    for i in range(0, n):  
        if (list[i] == key):  
            return i 
    return -1 

for word in split:
    file = f"{word}.mp3"
    file.lower()
    search_result = linear_search(dir_list, len(dir_list), file)
    if search_result == -1:
        print("Audio not found")
    else:
        playsound(f"Audio_tracks/{file}")
    time.sleep(0.16)

文本文件内容(供参考):

开始:1878年,我取得了伦敦大学医学博士学位,随后前往尼特利进修陆军外科医生的必修课程。学业完成后,我正式被任命为诺森伯兰第五燧发枪团的助理军医。当时该团驻扎在印度,我还没来得及报到,第二次阿富汗战争就爆发了。在孟买登陆后,我得知部队已经穿越隘口,深入敌境。于是我和其他处境相同的军官一起紧随其后,顺利抵达坎大哈,找到了所属部队,立刻开始履行新职责。这场战役为许多人带来了荣誉和晋升,对我而言却只有不幸和灾难。我被调离原属旅部,派往伯克郡团,随他们参加了惨烈的迈万德战役。在那里,我被一颗杰扎伊尔步枪子弹击中肩膀,击碎了骨头,还擦伤了锁骨下动脉。要不是我的勤务兵默里忠心耿耿、英勇无畏,把我扶到一匹驮马上,成功将我带回英军阵地,我早就落入那些残忍的加齐分子手中了。伤痛缠身,又历经长期艰苦磨难,我变得虚弱不堪,和大批伤员一起被转移到白沙瓦的后方医院。我在那里逐渐康复,已经能在病房里走动,甚至可以在阳台上晒晒太阳了,却又染上了肠热病——这是我们在印度属地的克星。有好几个月,大家都以为我没救了,最后我终于苏醒过来,开始康复,但身体已经极度虚弱消瘦,医疗委员会决定立即将我送回英国调养。于是我搭乘奥龙特斯号运兵船回国,一个月后在朴茨茅斯码头登陆,健康已无法挽回,但政府批准我接下来九个月的时间调养身体。我在英国举目无亲,因此像空气一样自由——或者说,像每天有11先令6便士收入的人能拥有的自由那样。在这种情况下,我自然而然地来到了伦敦,这个帝国所有游手好闲之辈都不由自主涌入的大污水坑。我在斯特兰德大街的一家私人旅馆住了一段时间,过着乏味无意义的生活,花钱也大手大脚,远超自己的承受能力。财务状况变得岌岌可危,我很快意识到,要么离开大都市去乡下定居,要么彻底改变生活方式。我选择了后者,决定先离开旅馆,找一个更朴实、更便宜的住处。就在我做出这个决定的当天,我站在克里奥尔酒吧,有人拍了拍我的肩膀,我转过身,认出了年轻的斯坦福,他以前在巴茨医院是我的助手。在伦敦这个茫茫人海中看到一张友好的面孔,对一个孤独的人来说真是件愉快的事。以前我和斯坦福算不上密友,但现在我热情地和他打招呼,他也似乎很高兴见到我。我欣喜不已,邀请他去霍尔本共进午餐,然后我们一起坐上了出租马车。“华生,你最近在忙什么?”他看着我,毫不掩饰地惊讶问道,马车在拥挤的伦敦街道上疾驰。“你瘦得像根木板,皮肤黑得像坚果。”我简短地给他讲了我的经历,刚说完我们就到了目的地。“可怜的家伙!”他听完我的不幸遭遇后同情地说。“你现在打算做什么?”“找住处,”我回答,“想看看能不能找到舒适又价格合理的房间。”“真巧,”我的同伴说,“今天你是第二个跟我说这话的人。”“第一个是谁?”我问。“是医院化学实验室的一个家伙。今天早上他还在抱怨,说找到了不错的房间,但房租太贵,找不到人合租。”“天哪!”我喊道,“如果他真的想找人合租分摊费用,那我正是合适的人选。我宁愿有个同伴,也不想独自居住。”斯坦福透过酒杯奇怪地看着我。“你还不认识夏洛克·福尔摩斯,”他说,“你可能不会喜欢和他长期同住。”“为什么,他有什么问题吗?”“哦,我不是说他有什么不好。他的想法有点古怪——对某些科学领域非常痴迷。据我所知,他是个正派的人。”“他是医学生吗?”我问。“不——我不知道他打算从事什么职业。我相信他精通解剖学,是一流的化学家,但据我所知,他从来没有上过系统的医学课程。他的学习杂乱无章、与众不同,但积累了大量冷门知识,足以让他的教授们大吃一惊。”“你从来没问过他打算从事什么吗?”我问。“没有;他不是那种容易吐露心声的人,但当他愿意的时候,也很健谈。”“我想见见他,”我说,“如果我要和别人同住,我更喜欢一个勤奋安静的人。我现在身体还不够强壮,受不了太多噪音和刺激。在阿富汗经历的那些已经够我受一辈子了。我怎么才能见到你的这位朋友?”“他肯定在实验室,”我的同伴回答,“他要么几周不去那里,要么从早到晚泡在里面。如果你愿意,我们午饭后一起过去。”“当然可以,”我回答,然后我们的话题转向了其他方面。

---

# 解决方案:使用多线程实现后台播放

核心思路是把音频播放任务放到**子线程**中执行,这样主线程的`for`循环无需等待播放完成即可继续迭代。Python的`threading`模块可以轻松实现这个需求,同时顺便修复你代码中的两个小问题:

1. `file.lower()`没有重新赋值,导致文件名大小写不匹配的问题
2. 手动实现的`linear_search`可以用Python内置的`in`运算符简化,更高效简洁

修改后的代码如下:
```python
import os
import threading
from playsound import playsound
import time

text = open("book.txt", encoding="utf-8").read()
split = text.split()
path = "Audio_tracks"
dir_list = os.listdir(path)

# 简化搜索逻辑,用in替代手动线性搜索
for word in split:
    file = f"{word}.mp3".lower()  # 直接转换为小写并赋值
    if file not in dir_list:
        print(f"Audio not found for: {word}")
    else:
        # 将播放任务放入子线程
        audio_path = os.path.join(path, file)
        threading.Thread(target=playsound, args=(audio_path,), daemon=True).start()
    time.sleep(0.16)

关键说明:

  • threading.Thread(target=playsound, args=(audio_path,), daemon=True):创建一个子线程,指定要执行的函数是playsound,传入的参数是音频文件路径
  • .start():启动子线程,音频会在后台播放,主线程立即继续执行下一次循环
  • daemon=True:设置为守护线程,这样当主线程结束时,所有后台播放的子线程会自动终止,避免程序残留进程

如果需要更精细的音频控制(比如暂停、停止),可以考虑使用更专业的音频库如pygame或pyaudio,但对于你的基础需求,threading+playsound已经足够解决阻塞问题。


内容的提问来源于stack exchange,提问作者Devesh Reddy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 12:40:14