pynput.Listener非阻塞启动时running属性输出不一致问题咨询
问题原因分析
这是典型的多线程异步执行导致的竞态条件,核心原因和pynput监听器的实现机制、操作系统线程调度逻辑有关:
Listener.start()是异步启动后台线程:pynput的
Listener本质基于Python的threading.Thread实现后台线程。调用l.start()时,只是向操作系统提交启动线程的请求,主线程会立刻继续执行后续代码,不会等待后台线程完成初始化(包括把running属性设为True)。操作系统线程调度的不确定性:Windows的线程调度是抢占式的,每次运行程序时,操作系统分配给后台监听器线程的执行时机完全不确定:
- 如果主线程的
print(l.running)先执行,此时监听器线程还没完成初始化,running保持初始值False; - 如果监听器线程刚好在主线程执行
print前完成初始化,running就会是True。
这就是运行结果时好时坏的直接原因。
- 如果主线程的
调试/添加代码后行为稳定的原因:
- 调试时,断点或单步执行会让主线程暂停,给了监听器线程足够时间完成初始化,所以
running必然是True; - 在
l.start()后添加代码(哪怕是空语句或者短延时),会拉长主线程执行到print(l.running)的时间,让监听器线程有更大概率完成初始化,因此输出True的概率提升。
- 调试时,断点或单步执行会让主线程暂停,给了监听器线程足够时间完成初始化,所以
另外你观察到的“先输出False再进入循环”的情况,是因为主线程执行print(l.running)时监听器还没就绪,但进入while循环后,主线程执行sleep(1),这1秒内监听器线程完成了初始化,running变成True,所以循环会继续执行。
内容的提问来源于stack exchange,提问作者101is5
相关产品推荐
相关产品推荐

