我是Tcl的初学者。我试图学习Tcl而不参与Tk。我遇到了像vwait
和after
这样的命令,但我很困惑,因为大多数解释涉及event loop
的概念,并且进一步主要通过使用Tk来证明这个概念。我想了解事件和事件循环的概念以及我提到的命令如何与它们相关,请参考我的一些参考。解释不应该使用Tk作为示例,不使用Tcl扩展,假设没有事件的先验知识。除了GUI编程/ Tk之外,一些(最小的)玩具示例和tcl事件循环的真实wordl应用将是值得赞赏的。
我在Tclers维基上看到了这个tutorial。我正在寻找其他参考或这样的解释。
答案 0 :(得分:4)
如果您没有使用Tk,使用事件循环的主要原因是在执行其他I / O绑定任务时在后台等待,以及处理服务器套接字。
让我们看看服务器套接字。
使用以下命令打开服务器套接字时
socket -server myCallbackProcedure 12345
您正在安排在服务器套接字上设置事件处理程序,以便在有传入连接时,该连接转换为普通套接字,并且调用您提供的回调过程(myCallbackProcedure
)处理与套接字的交互。这通常是通过设置一个fileevent
处理程序来完成的,以便在传入数据到达时处理它而不是阻止等待它的进程,但它不一定是。
事件循环?这是调用操作系统的一段代码(通过select()
,poll()
,WaitForMultipleObject()
等,具体取决于操作系统和构建选项),等待任何指定频道发生事件或发生超时。它非常有效,因为在等待时可以暂停进行呼叫的线程。如果发生某些事情,OS调用返回并且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