Python钓鱼机器人计时器无法循环重启问题排查
1. 计时器初始化时音频处理器引用为空
在GUI.py的初始化流程中,fishing_timer创建时传入的audio_processor参数还未完成初始化,导致fishing_timer内部的audio_processor始终为None:
# 错误顺序:先创建timer,再初始化audio_processor fishing_timer = CountdownTimer(5, fishing_timer_update_callback, fishing_timer_end_callback, audio_processor) audio_processor = AudioStreamProcessor(timer=fishing_timer, on_detection_callback=fish_hooked)
这直接导致CountdownTimer._run()方法中检测音频触发的代码块完全失效,计时过程中无法响应任何音频检测事件。
修复方法:调整初始化顺序,先完成audio_processor的创建,再将其传入fishing_timer:
# 正确顺序:先初始化audio_processor audio_processor = AudioStreamProcessor(on_detection_callback=fish_hooked) fishing_timer = CountdownTimer(5, fishing_timer_update_callback, fishing_timer_end_callback, audio_processor) audio_processor.set_timer(fishing_timer) # 绑定timer到audio_processor
2. 计时器线程状态管理混乱
CountdownTimer.start()仅通过_timer_thread is None判断是否启动新线程,但在handle_detection()或end_callback()中调用start()时,原线程可能仍在执行收尾逻辑(将_timer_thread设为None),导致新线程的引用被覆盖,最终丢失线程引用,is_running()判断彻底失效。
同时,_run()方法处理音频检测后执行break,随后会触发end_callback(),而end_callback()又会调用reset()和start(),造成重复启动,进一步干扰线程状态。
修复方法:
- 在
handle_detection()中先停止当前线程,再重置启动:
def handle_detection(self): self.stop() # 先终止当前计时器线程 pyautogui.press('f') time.sleep(2) self.reset() self.start() pyautogui.press('1')
- 修改
_run()方法,处理音频检测后直接返回,避免触发后续的end_callback():
def _run(self): while self.remaining > 0 and not self._stop_flag: time.sleep(1) self.remaining -= 1 if self.update_callback is not None: self.update_callback(self.remaining) # 处理音频检测后直接返回,跳过end_callback逻辑 if self.audio_processor and self.audio_processor.detected: if hasattr(self, 'handle_detection'): self.handle_detection() return if not self._stop_flag: if self.end_callback: self.end_callback() self.last_start_time = time.time() self._timer_thread = None
3. 音频检测状态的线程安全问题
AudioStreamProcessor.detected变量在PyAudio回调线程和计时器线程中被同时读写,但没有任何同步机制,可能导致状态读取不一致。例如,计时器线程读取到detected=True时,音频回调线程可能正在将其设为False,引发逻辑混乱。
修复方法:使用threading.Lock保护detected变量的读写操作:
# 在AudioStreamProcessor类中添加锁 class AudioStreamProcessor: def __init__(self, timer=None, on_detection_callback=None): # ... 其他初始化代码 ... self.detected_lock = threading.Lock() self.detected = False # 修改callback中的detected赋值逻辑 def callback(self, in_data, frame_count, time_info, status): # ... 音频处理逻辑 ... current_time = time() with self.detected_lock: if self.max_correlation > self.THRESHOLD: if current_time - self.last_detected_time > self.debounce_period: self.last_detected_time = current_time self.detected = True if self.timer: self.timer.handle_detection() if self.on_detection_callback: self.on_detection_callback() else: self.detected = False else: self.detected = False # ... 返回逻辑 ... # 在CountdownTimer._run()中读取detected时加锁 def _run(self): while self.remaining > 0 and not self._stop_flag: time.sleep(1) self.remaining -= 1 if self.update_callback is not None: self.update_callback(self.remaining) # 加锁读取detected状态 if self.audio_processor: with self.audio_processor.detected_lock: if self.audio_processor.detected: if hasattr(self, 'handle_detection'): self.handle_detection() return # ... 后续逻辑 ...
内容的提问来源于stack exchange,提问作者Chris Dk

