events - Tcl 中的事件循环

标签 events tcl

我是 Tcl 的初学者。我正在尝试学习 Tcl 而不涉及 Tk。我遇到过像 vwait 和 after 等命令,但我很困惑,因为大多数解释都涉及事件循环的概念,并且进一步主要通过使用来演示这个概念知道。我想了解事件和事件循环的概念以及我提到的命令如何与它们相关,请引用我的一些引用资料。解释不应使用 Tk 作为示例,不使用 Tcl 扩展,假设没有事件的先验知识。除了 GUI 编程/Tk 之外,一些(最小的)玩具示例和 tcl 事件循环的实际应用将受到赞赏。

我遇到了这个tutorial在 Tclers 维基上。我正在寻找类似的其他引用或解释。

最佳答案

如果您不使用 Tk,那么使用事件循环的主要原因是在执行其他一些 I/O 密集型任务时在后台等待,以及处理服务器套接字。

让我们看看服务器套接字。

当您使用以下命令打开服务器套接字时:

socket -server myCallbackProcedure 12345

您正在安排在服务器套接字上设置一个事件处理程序,以便在有传入连接时,该连接将转换为普通套接字和您提供的回调过程 (myCallbackProcedure)被调用来处理与套接字的交互。这通常是通过设置 fileevent 处理程序来完成的,以便传入数据在到达时得到处理,而不是阻塞等待它的进程,但这不是必须的。

事件循环?这是一段调用操作系统的代码(通过 select()poll()WaitForMultipleObject() 等,具体取决于操作系统和构建选项)等待任何指定 channel 上发生某些情况或发生超时。它非常高效,因为进行调用的线程可以在等待时挂起。如果发生某些情况,操作系统调用将返回,并且 Tcl 会安排调用相关回调。 (内部有一个队列。)这是一个循环,因为一旦处理了事件,通常会返回并等待更多事件。 (这就是 Tk 所做的事情,直到没有更多的窗口可供它控制,以及 vwait 所做的事情,直到它正在等待的变量被某个事件处理程序设置为止。)

异步等待使用按时间排序的队列进行管理,并转化为设置操作系统调用的超时。

一个例子:

socket -server myCallbackProcedure 12345
proc myCallbackProcedure {channel clientHost clientPort} {
    puts "Connection from $clientHost"
    puts $channel "Hi there!"
    flush $channel
    close $channel
}
vwait forever
# The “forever” is an idiom; it's just a variable that isn't used elsewhere
# and so is never set, and it indicates that we're going to run the process
# until we kill it manually.

一个更复杂的异步连接处理示例,因此我们可以一次提供多个连接(所需的 CPU:最少):

socket -server myCallbackProcedure 12345
proc myCallbackProcedure {channel clientHost clientPort} {
    puts "Connection from $clientHost"
    fileevent $channel readable [list incoming $channel $clientHost]
    fconfigure $channel -blocking 0 -buffering line
    puts $channel "Hi there!"
}
proc incoming {channel host timeout} {
    if {[gets $channel line] >= 0} {
        puts $channel "You said '$line'"
    } elseif {[eof $channel]} {
        puts "$host has gone"
        close $channel
    }
}
vwait forever

一个更复杂的示例,它将在最后一条消息发送后 10 秒(= 10000 毫秒)关闭连接:

socket -server myCallbackProcedure 12345
proc myCallbackProcedure {channel clientHost clientPort} {
    global timeouts
    puts "Connection from $clientHost"
    set timeouts($channel) [after 10000 [list timeout $channel $clientHost]]
    fileevent $channel readable [list incoming $channel $clientHost]
    fconfigure $channel -blocking 0 -buffering line
    puts $channel "Hi there!"
}
proc incoming {channel host timeout} {
    global timeouts
    after cancel $timeouts($channel)
    if {[gets $channel line] >= 0} {
        puts $channel "You said '$line'"
    } elseif {[eof $channel]} {
        puts "$host has gone"
        close $channel
        unset timeouts($channel)
        return
    }
    # Reset the timeout
    set timeouts($channel) [after 10000 [list timeout $channel $host]]
}
proc timeout {channel host} {
    global timeouts
    puts "Timeout for $host, closing anyway..."
    close $channel
    unset -nocomplain timeouts($channel)
}
vwait forever

关于events - Tcl 中的事件循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28315091/

相关文章:

iphone - 如何发送 UIEvent TypeRemoteControl 事件?

tcl - WordNet 3.0 无法安装在 OS X Mountain Lion (10.8) 上

macos - 如何从 tcl 脚本应用程序为 mac os x 创建 .app

TCL 中带空格的字符串路径不起作用

c# - 没有事件处理程序的绑定(bind)事件..为什么有效?

javascript - 有什么方法可以在 osx 浏览器的 javascript 中检测 ctrl + 单击?没有 jQuery

php - Magento 调度自定义事件不起作用

shell - 执行tclsh时需要什么shell

compiler-errors - 如何在Ubuntu 17.10上编译WordNet-3.0?

javascript - 当鼠标进入父级时如何显示元素?