Python 解释器使用什么机制来进行事件驱动编程?
What mechanisms does the Python interpreter use to be able to do event-driven programming?
我是事件驱动编程的新手,当 CPython 解释器逐行检查代码时,我真的很想更好地理解幕后发生的事情。到目前为止,我只按顺序编程,而且我对解释器如何将我的代码转换为字节码,然后从一个语句转到下一个语句并执行命令有一个很好的想法。
但是对于事件驱动编程,我完全搞不懂解释器是如何工作的。
特别迷茫
解释器如何知道在源代码中下一步跳转到哪里
还有特定事件发生时如何调用函数处理程序
事件循环的刷新率是如何处理的:其实就是函数的所有代码每秒处理运行千次,但是因为某种"event-has-not-happened" 标记说 "don't execute this function now"?
为了使讨论更加具体,您能否在以下示例中说明这些要点,该示例取自 site:
from Tkinter import *
ROOT = Tk()
def ask_for_userinput():
user_input = raw_input("Give me your command! Just type \"exit\" to close: ")
if user_input == "exit":
ROOT.quit()
else:
label = Label(ROOT, text=user_input)
label.pack()
ROOT.after(0, ask_for_userinput)
LABEL = Label(ROOT, text="Hello, world!")
LABEL.pack()
ROOT.after(0, ask_for_userinput)
ROOT.mainloop()
理想情况下,我想要一个与 this 文章类似的解释,从 CPython 解释器如何工作的角度解释了为什么有些语句是线程安全的,而有些不是,线程安全是如何实现的。
事件循环所做的就是在事件发生时调用其他函数。图形子系统通过向事件循环发出事件正在等待处理的信号来提供帮助。
键盘输入和鼠标交互(移动指针、单击)等事件均由图形子系统 (GUI) 和操作系统 (OS) 处理。键盘和鼠标是硬件设备,计算机使用 interrupts 记录它们的状态以供 GUI 使用。
如果您不触摸键盘或鼠标,事件循环就什么也做不了;循环 块 和 OS 将执行其他进程,因为循环已发出信号,它正在等待某事发生。此时 OS 处于控制之中,没有给进程任何 CPU 时间,而是给其他进程 运行。一旦发生某些事情,队列中就会有事件,OS 可以恢复该过程。想象一下事件循环中的一个函数调用,询问是否有更多事件,并且该调用不会 return 直到有。
循环恢复后,队列中有事件要处理('mouse position is now x, y'、'the keyboard input queue contains the characters F, O, and O')。每个事件都可以触发代码你写的,并在该事件上注册为运行。例如,您可以在单击按钮时将处理程序注册为 运行;事件框架有一个注册表,如果条件正确('mouse button click' 事件发生,光标位于屏幕上的正确位置,按钮处于活动状态且可见),那么知道调用您的自定义事件处理程序。
这样的事件处理程序是 完全同步的,如果处理程序需要很长时间才能完成,您会注意到您的 GUI 'freezes' 没有执行任何其他操作,因为Python 运行 那个处理程序太忙了。通常的 work-around 是在那种情况下使用线程;您的事件处理程序会快速启动一个单独的线程来完成真正的工作,然后 returns。这样主线程(带有事件循环)可以处理下一个事件,而 OS 在额外线程和主线程中的工作之间切换。
至于您发布的具体代码,这实际上不是一个很好的例子。它主动忽略 GUI 输入,而是使用raw_input()
函数从控制台捕获键盘输入。每次 运行s!
函数时,GUI 都被完全阻塞
ask_for_userinput()
函数 是 一个事件处理程序,它被注册为一个 after()
method. after()
uses a timer interrupt, (usually implemented with a SIGALRM
interrupt) 在至少 0 秒后被调用(所以 尽快 ,真的)。每次调用它时,它都会向 GUI(只是一段文本)和 re-schedules 本身添加一个新标签。不是很有趣!
我是事件驱动编程的新手,当 CPython 解释器逐行检查代码时,我真的很想更好地理解幕后发生的事情。到目前为止,我只按顺序编程,而且我对解释器如何将我的代码转换为字节码,然后从一个语句转到下一个语句并执行命令有一个很好的想法。
但是对于事件驱动编程,我完全搞不懂解释器是如何工作的。
特别迷茫
解释器如何知道在源代码中下一步跳转到哪里
还有特定事件发生时如何调用函数处理程序
事件循环的刷新率是如何处理的:其实就是函数的所有代码每秒处理运行千次,但是因为某种"event-has-not-happened" 标记说 "don't execute this function now"?
为了使讨论更加具体,您能否在以下示例中说明这些要点,该示例取自 site:
from Tkinter import *
ROOT = Tk()
def ask_for_userinput():
user_input = raw_input("Give me your command! Just type \"exit\" to close: ")
if user_input == "exit":
ROOT.quit()
else:
label = Label(ROOT, text=user_input)
label.pack()
ROOT.after(0, ask_for_userinput)
LABEL = Label(ROOT, text="Hello, world!")
LABEL.pack()
ROOT.after(0, ask_for_userinput)
ROOT.mainloop()
理想情况下,我想要一个与 this 文章类似的解释,从 CPython 解释器如何工作的角度解释了为什么有些语句是线程安全的,而有些不是,线程安全是如何实现的。
事件循环所做的就是在事件发生时调用其他函数。图形子系统通过向事件循环发出事件正在等待处理的信号来提供帮助。
键盘输入和鼠标交互(移动指针、单击)等事件均由图形子系统 (GUI) 和操作系统 (OS) 处理。键盘和鼠标是硬件设备,计算机使用 interrupts 记录它们的状态以供 GUI 使用。
如果您不触摸键盘或鼠标,事件循环就什么也做不了;循环 块 和 OS 将执行其他进程,因为循环已发出信号,它正在等待某事发生。此时 OS 处于控制之中,没有给进程任何 CPU 时间,而是给其他进程 运行。一旦发生某些事情,队列中就会有事件,OS 可以恢复该过程。想象一下事件循环中的一个函数调用,询问是否有更多事件,并且该调用不会 return 直到有。
循环恢复后,队列中有事件要处理('mouse position is now x, y'、'the keyboard input queue contains the characters F, O, and O')。每个事件都可以触发代码你写的,并在该事件上注册为运行。例如,您可以在单击按钮时将处理程序注册为 运行;事件框架有一个注册表,如果条件正确('mouse button click' 事件发生,光标位于屏幕上的正确位置,按钮处于活动状态且可见),那么知道调用您的自定义事件处理程序。
这样的事件处理程序是 完全同步的,如果处理程序需要很长时间才能完成,您会注意到您的 GUI 'freezes' 没有执行任何其他操作,因为Python 运行 那个处理程序太忙了。通常的 work-around 是在那种情况下使用线程;您的事件处理程序会快速启动一个单独的线程来完成真正的工作,然后 returns。这样主线程(带有事件循环)可以处理下一个事件,而 OS 在额外线程和主线程中的工作之间切换。
至于您发布的具体代码,这实际上不是一个很好的例子。它主动忽略 GUI 输入,而是使用raw_input()
函数从控制台捕获键盘输入。每次 运行s!
ask_for_userinput()
函数 是 一个事件处理程序,它被注册为一个 after()
method. after()
uses a timer interrupt, (usually implemented with a SIGALRM
interrupt) 在至少 0 秒后被调用(所以 尽快 ,真的)。每次调用它时,它都会向 GUI(只是一段文本)和 re-schedules 本身添加一个新标签。不是很有趣!