Python闹钟代码问题:播放助眠音效时While循环无法终止触发闹钟
Hey there! Let's break down why your sleep sound's while loop is blocking your alarm from playing—this is a super common snag when dealing with audio playback and looped tasks in Python.
The Core Issue: Blocking Threads
Chances are your while loop for the sleep sound is running in the main thread and using a blocking audio playback method (like playsound() which waits for the audio to finish before moving on). This means your entire program gets stuck looping the sleep sound, and never gets the chance to check if it's time for the alarm to trigger. Even moving the loop into the alarm function won't fix this because the main thread is still tied up.
Solution: Use Multithreading to Separate Tasks
The fix is to run the sleep sound playback in a separate background thread, so your main thread can keep monitoring the time for the alarm. Here's a step-by-step implementation:
1. Set Up Thread-Safe Termination
Instead of a simple boolean flag, use threading.Event()—it's designed for safe communication between threads to signal when a task should stop.
2. Example Code with playsound
import time import threading from playsound import playsound # Thread-safe flag to stop the sleep sound stop_sleep_event = threading.Event() def play_continuous_sleep_sound(): """Play sleep sound on loop until told to stop""" while not stop_sleep_event.is_set(): # playsound() is blocking, so it'll wait for the sound to finish before looping playsound("city_sleep_sound.mp3") def run_alarm(alarm_target_time): # Start the sleep sound in a background thread sleep_thread = threading.Thread(target=play_continuous_sleep_sound) sleep_thread.start() # Main thread monitors the time print(f"Alarm set for {alarm_target_time}") while True: current_time = time.strftime("%H:%M:%S", time.localtime()) if current_time == alarm_target_time: print("WAKE UP! 🚨") # Signal the sleep sound thread to stop stop_sleep_event.set() # Wait for the sleep thread to fully terminate sleep_thread.join() # Play the alarm sound playsound("alarm_sound.mp3") break # Check time every second to avoid hogging CPU time.sleep(1) if __name__ == "__main__": # Replace with your desired alarm time (HH:MM:SS) run_alarm("08:30:00")
3. Better Option: Non-Blocking Audio with Pygame
If you want seamless looping (no gap between sleep sound repeats) and more control over audio playback, use pygame.mixer which supports non-blocking play:
import pygame import time import threading pygame.mixer.init() stop_sleep_event = threading.Event() def play_continuous_sleep_sound(): pygame.mixer.music.load("city_sleep_sound.mp3") # Play on loop (-1 = infinite loop) pygame.mixer.music.play(-1) # Wait until we get the stop signal while not stop_sleep_event.is_set(): time.sleep(0.1) # Prevent empty loop from eating CPU pygame.mixer.music.stop() def run_alarm(alarm_target_time): sleep_thread = threading.Thread(target=play_continuous_sleep_sound) sleep_thread.start() print(f"Alarm active, waiting for {alarm_target_time}...") while True: current_time = time.strftime("%H:%M:%S", time.localtime()) if current_time == alarm_target_time: print("Time to wake up!") stop_sleep_event.set() sleep_thread.join() # Play alarm sound pygame.mixer.music.load("alarm_sound.mp3") pygame.mixer.music.play() # Wait for alarm to finish playing while pygame.mixer.music.get_busy(): time.sleep(0.1) break time.sleep(1) if __name__ == "__main__": run_alarm("09:00:00")
Key Tips to Avoid This Issue Again
- Never block the main thread: Any long-running or looped task (like audio playback) should run in a background thread.
- Use thread-safe signals:
threading.Event()is more reliable than a simple boolean for stopping threads across different execution contexts. - Avoid tight loops: Add small
time.sleep()calls in loops to reduce CPU usage.
内容的提问来源于stack exchange,提问作者Riley Carpenter

