【问题标题】:What mechanisms does the Python interpreter use to be able to do event-driven programming?Python 解释器使用什么机制来进行事件驱动编程?
【发布时间】:2018-02-17 13:14:00
【问题描述】:

我是事件驱动编程的新手,我真的很想更好地了解当 CPython 解释器逐行遍历代码时会发生什么。到目前为止,我只进行了顺序编程,并且我对解释器如何将我的代码转换为字节码然后从一条语句转到下一条语句并执行命令有一个相当好的想法。

但是对于事件驱动的编程,我完全搞不懂解释器是如何工作的。

我特别困惑

  1. 解释器如何知道在源代码中下一步跳转到哪里

  2. 还有在某些事件发生时如何调用函数处理程序

  3. 事件循环的刷新率是如何处理的:实际上是函数句柄的所有代码每秒运行数千次,但由于某种“事件未发生”标志而没有执行说“现在不要执行这个函数”?

为了使讨论更具体,您能否在以下示例中说明这些要点,取自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 解释器如何工作的角度进行了精彩的解释,为什么有些语句是线程安全的而有些不是,以及如何实现了线程安全。

【问题讨论】:

    标签: python events interpreter


    【解决方案1】:

    事件循环所做的只是在事件发生时调用其他函数。图形子系统通过向事件循环发出事件正在等待处理的信号来提供帮助。

    键盘输入和鼠标交互(移动指针、单击)等事件均由图形子系统 (GUI) 和操作系统 (OS) 处理。键盘和鼠标是硬件设备,计算机使用interrupts 记录它们的状态以供 GUI 获取。

    如果您不触摸键盘或鼠标,事件循环将无能为力;循环阻塞,并且操作系统将执行其他进程,因为循环已发出信号,它正在等待某些事情发生。此时操作系统处于控制之中,进程没有得到任何 CPU 时间,而是运行其他进程。一旦发生某些事情,队列中就会有事件,操作系统可以恢复该过程。想象一下事件循环中的函数调用,它询问是否还有更多事件,并且在有事件之前该调用不会返回。

    一旦循环继续,队列中有事件要处理('鼠标位置现在是 x,y','键盘输入队列包含字符 F、O 和 O')。每个事件都可以触发 编写的代码,并注册以在该事件上运行。例如,您可以注册一个处理程序以在单击按钮时运行;事件框架有一个注册表,如果条件正确(“鼠标按钮单击”事件发生,光标位于屏幕上的正确位置,按钮处于活动状态且可见),则知道调用您的自定义事件处理程序。

    这样的事件处理程序是完全同步的,如果处理程序需要很长时间才能完成,你会注意到你的 GUI '冻结',什么都不做,因为 Python 太忙于运行那个处理程序。通常的解决方法是在这种情况下使用线程;您的事件处理程序会快速启动一个单独的线程来完成实际工作,然后返回。这样主线程(带有事件循环)可以处理下一个事件,而操作系统在额外线程和主线程中的工作之间切换。

    至于您发布的具体代码,这实际上不是一个很好的示例。它主动忽略 GUI 输入,而是使用raw_input() 函数从控制台捕获键盘输入。每次函数运行时,GUI 都会完全阻塞!

    ask_for_userinput() 函数一个事件处理程序,它与after() method 注册为一个。 after() 使用定时器中断,(通常用 SIGALRM interrupt 实现)在至少 0 秒后被调用(所以尽快,真的)。每次调用它时,它都会向 GUI 添加一个新标签(只是一段文本)并重新安排自己的时间。不是很有趣!

    【讨论】:

    • +1 那么这意味着关于 a)ROOT.mainloop() 语句中的 Python 解释器“转发”该语句到 Tcl,然后 Tcl 又使用 OS 函数来监听事件?我不确定 Python 线程是否是解决此问题的方法,因为 GIL,Python 只能运行 1 个线程。
    • 是否有一些 CPU 时钟周期决定了中断发生的速度,以便操作系统响应。事件循环可以对它们做出反应吗?
    • @user47574:Python 可以运行大量线程。 Python 不能做的是并行 运行Python 线程。 GIL 不会阻止 并发,在处理 GUI 事件和每秒数百次运行时间较长的繁重任务之间切换。
    • @user47574:GIL 意味着 Python 线程不能用于加速繁重的计算任务(只要每个线程都必须等待轮到它们的 CPU 时间,因为线程是切换)。非 Python 代码(扩展)可以释放 GIL 并安排在单独的 CPU 内核上运行,因此它们可以并行运行。见Does Python support multithreading? Can it speed up execution time?
    • @user47574:这在很大程度上取决于 CPU 架构和确切的操作系统如何处理中断。无论如何,这些周期比人类的反应时间要快得多。
    猜你喜欢
    • 2011-06-14
    • 2012-05-06
    • 1970-01-01
    • 2014-06-22
    • 2011-04-23
    • 1970-01-01
    • 2015-10-06
    • 1970-01-01
    • 2014-01-03
    相关资源
    最近更新 更多