我还是TCL的新手,不要太多使用它,主要是遗留代码。我遇到代码问题,通过简化代码,我得到了下面的代码。在第二个“之后”我有一个有时需要更长时间的代码,有时比第一个“之后”更快。我希望我的代码在其中任何一个完成时继续,而忽略另一个。但是,我的vwait总是在等待最新的“之后”。
global tkf
set tkf b
puts "ini: $tkf"
# wait 7 seconds, then set tkf
set aid7 [after 7000 set tkf Y7]
puts "7: $tkf ($aid7)"
# wait 4 seconds, then wait 15 seconds, then set tkf
after 4000 {
puts "will wait 15s"
after 15000
puts "waited, will set tkf 4"
set tkf Y4
}
puts "4: $tkf"
vwait tkf
puts "vwait $tkf"
puts "end"
我希望这会在7秒内触发我的视听,然后继续。但这是我得到的输出:
E:\>tclsh vwait_test.tcl
ini: b
7: b (after#0)
4: b
will wait 15s
waited, will set tkf 4
vwait Y4
end
这意味着它等了15秒并触发了设置tkf的第二个代码。我以为它会输出:
will wait 15s
vwait Y7
end
我不知道为什么这是它的行为或如何改变它,我无法在文档页面上得到任何提示。如果有人能向我解释这种行为,以及如何得到我想要的东西,我会很感激。然后我可以根据自己的代码进行调整。
答案 0 :(得分:2)
已经有一段时间了,因为我已经深入研究了这个问题,但看起来好像在4秒后你让整个应用程序进入睡眠状态15秒。执行after 15000
时,15秒内不会发生任何事情,因为tcl是单线程的。
更清楚一点:after X
和after X {script}
之间存在差异。前者与“睡眠”相同。命令 - 该程序在这段时间内暂停。后者,而不是睡觉,安排一些代码在未来的某个时间运行。
这在后手册页上有记录。这是一个相关的引用:
ms后Ms必须是一个整数,以毫秒为单位给出时间。该 命令休眠ms毫秒,然后返回。而命令 正在睡觉的应用程序没有响应事件。
上述内容取自http://tcl.tk/man/tcl8.5/TclCmd/after.htm#M5
在此背景下,"事件"包括使用after
本段紧接在手册页中:
在ms?脚本脚本脚本之后? 在此形式中,命令返回 立即,但它安排执行一个Tcl命令ms 毫秒后作为事件处理程序。该命令将被执行 在给定的时间恰好一次。延迟命令由。形成 以与。相同的方式连接所有脚本参数 concat命令。该命令将在全局级别(外部)执行 任何Tcl程序的上下文)。如果执行时发生错误 延迟命令然后将报告后台错误 用interp bgerror注册的命令。 after命令返回一个 可用于使用after取消延迟命令的标识符 取消。
答案 1 :(得分:2)
为了记录和未来的参考,我根据schlenk和Bryan Oakley的评论,对我所理解的情况进行了扩展解释。谢谢你们两个。
带有命令的after
并未在后台睡觉,以便在此时触发。相反,它保存在名为“事件循环”的结构中,并且仅在调用某些特定命令时执行,这些命令会导致处理事件循环。
以下是代码中发生的事情:
首先,它将after 7000
代码(set tkf Y7
)添加到事件循环,以便在7秒后执行。只有当事件循环被触发时才会执行此操作,此时它将检查7秒条件。
然后它将after 4000
块添加到事件循环,也不执行它。
然后它到达vwait
。此命令将触发事件循环,但现在没有任何内容可执行,因此它什么都不做。由于vwait
将继续运行事件循环,直到变量发生变化,因此主代码不会继续前进。相反,vwait
将继续重复事件循环直到发生某些事情。但是前4秒没有任何事情发生。最后,在4秒后,事件循环注意到after 4000
块已准备好执行。因此,事件循环完整地执行该块。
after 4000
块将打印一条消息并休眠15秒。此时,主代码未运行,因为它正在等待vwait
。 vwait
正在运行事件循环,现在正在等待,因为事件循环找到了要执行的事件; 事件循环正在运行此块,正在执行睡眠。一旦15秒过去,我们仍在块内继续,打印另一条消息并使用set tkf Y4
设置tkf。之后,块就完成了。
事件循环仍有一个可以运行的待处理事件after 7000
,上次事件循环检查时其条件未满足但是如果事件循环现在检查它将被满足。但是,当块完成运行时,满足vwait
条件。这意味着事件循环不会移动到下一个事件,因此它不会执行after 7000
,并且控件将返回到具有puts "vwait $tkf"
的主代码
事情永远不会并行运行,并且总是只有一个线程。 “事件循环”是一个并行结构,但它不是独立运行的。这意味着在+ vwait之后制作我想要的东西是不可能的。我想在我们的主代码之后继续完成第一次运行后,在他们并行运行的印象下。但是第一次完成将始终是第一个开始运行,因为它们并不是并行运行。另外,我对vwait总是在等待最新“之后”的解释是错误的。实际上,它只是等待最短的“之后”。
现在可以找到替代方案,可能还有线程......: - /