我有一个tcl脚本,但一次只能解压缩一件事。 我现在必须等待它完成的那一刻,然后才能完成下一个。我如何一次做两件事?
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"
if {[catch {exec /bin/sh -c "unrar e $dir/$name $dir/archive/$name"} error]} {
putlog "error: $error";
}
}
此致
答案 0 :(得分:1)
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
,因为这样就可以看到 已完成的内容;了解正在发生的事情偶尔会出现异步程序问题,因此确切地说是有帮助的。 (这是一个明确的专家!)
您可以根据需要一次启动多次。做太多(多少取决于你的硬件),你的电脑会慢下来,可能很多,但它最终会赶上来。