Tcl 可以同时做几件事,特别是当它本身在等待时会受到 I/O 限制。要做到这一点,我们需要利用 eggdrop (我认识那种类型的bind
)正在运行事件循环的事实,并使用fileevent
命令。该fileevent
命令很棒,因为它可以让我们安排一些代码在频道上“发生某事”时运行;当通道是管道(或套接字)时,当有一些文本要读取或通道关闭时,可以使用可读事件来做某事。(在您真正阅读某些内容之前,很难区分差异。)
让我们把这些位放在一起:管道和结果报告。我提出asyncpipe
命令!
proc asyncpipe {command lineCallback closedCallback} {
set f [open |$command "r"]
fileevent $f readable [list asyncpipe.callback $f $lineCallback $closedCallback]
# There's no output from this command directly, and it returns nearly instantly if your pipeline is sensible.
}
proc asyncpipe.callback {channel lineCallback closedCallback} {
if {[gets $channel line] >= 0} {
uplevel "#0" $lineCallback [list $line]
} elseif {[eof $channel]} {
catch {close $channel}
uplevel "#0" $closedCallback
}
}
好的,这是构建基本机器,但还不是特别清楚。以下是如何使用它。
bind pubm - "*complete*" unrar
proc unrar {nick host handle channel text} {
set text [stripcodes bcru $text]
set name [lindex [split $text] 2];
set dir "/tmp/unrar"
asyncpipe [list unrar e $dir/$name $dir/archive/$name] \
[list unrar.report putlog $name] [list unrar.done $name]
}
proc unrar.report {name line} {
putlog "unrar $name :>> $line"
}
proc unrar.done {name} {
putlog "all done with unrar $name"
}
这将在发生时报告 unrar 的输出,它会让你一次运行两个。(编写一个使用 unzip 代替的“副本”作为练习;除了可能要解压缩的参数之外,这完全是一个剪切-粘贴的工作。)异步编程比您习惯的要复杂一些,但是只要您对回调使用命名过程,您就可以工作而不会太困惑。
忽略机器,专注于更高层次上正在发生的事情。重写unrar
解析其参数并要求unrar
作为子进程异步运行。每当有输出时,它就会被触发unrar.report
(一次一行)将其写入日志。您可能还想在其他地方报告它/以及。当管道完成时,unrar.done
被调用以便它可以记录它已经完成。我将名称传递给unrar.report
,unrar.done
因为这样就可以看到完成的内容;了解正在发生的事情有时是异步程序的一个问题,因此准确地说是有帮助的。(这是一个明确的专业提示!)
您可以一次启动任意多次。做太多(多少取决于您的硬件),您的计算机会变慢,可能很多,但它最终会赶上。