因为在用
Perl-Tk
或者
Socket
时,经常会需要监视某些打开的句柄而不至于阻塞主循环,
对于这些 win32
下的
Perl
表现远不如
Linux
下来得得心应手,但这时候我基本没有什么办法。这和
windows
的底层
select
实现有关,而
Perl
恰恰是调用它的,但我一直认为肯定有别的替代办法,因为
Tcl/Tk
的
fileevent
就表现得很好。
下面是一个例子,用来显示
ping
的结果。这里有两个组件,一个是按钮,用来开始和停止
ping
;另一个是
text
用来显示
ping
的结果。分别用
Perl
和
Tcl/Tk
代码来实现,看看他们有什么不同。
use Tk;
$count = 4;
$host = '127.0.01';
$mw = MainWindow->new;
$bt = $mw->Button(-text => 'Clink to start ping', -command => \&RunPing);
$bt->pack(-fill => 'x');
$tx = $mw->Text(-width => 50, -height => 30);
$tx->pack;
MainLoop;
sub RunPing {
open $fd, "ping -n $count $host|";
$mw->fileevent($fd, 'readable' => sub {
sysread $fd, $buf, 30;
$tx->insert('end', $buf);
});
$bt->configure(-text => 'close', -command => \&ClosePing);
}
sub ClosePing {
close $fd;
undef $fd;
$bt->configure(-text => 'Clink to start ping', -command => \&RunPing);
}
运行的结果很让人失望,在
readable
的事件中加入
print
后而已更清楚地看到,事实上
readable
事件是没有被触发过的。这里的
fileevent
是
Tk
中处理事件触发的函数,它为句柄的两个状态(
readable
,
writable
)设定触发函数,其本质上使用了系统的
select
或者
poll
,换句话说即便是用
Perl
的
select
或者
IO::Seelct
也是于事无补。文档里的原话佐证了这点“
A file is considered to be readable on same basis as the system's select() (or poll()).
”。
所以可以这么讲,
win32
下的
Perl
是不大适合处理事件响应的,因而也就很难处理好处理网络相关或者界面需要运行后台长时间操作的情况。接下来换作是使用
Tcl/Tk
来实现这一功能,值得一提的是在
Perl
下
50
宽度的
button
和
text
是不等长的,所以索性在
pack
里用
fill
自动拓宽了,而在
Tcl/Tk
中没有这个问题。
package require Tk
set pingcount 4
set host {127.0.0.1}
button .btn -text {Clink to start ping} -command "RunPing $host $pingcount" -width 50
text .text -width 50 -height 30
pack .btn .text
proc RunPing {host count} {
set fd [open "|ping -n $count $host"]
;#fconfigure $fd -blocking 0
fileevent $fd readable "onPingRead $fd $count $host"
.btn configure -text "close" -command "closeFd $fd $count $host"
}
proc onPingRead {fd count host} {
if {[eof $fd]} {
closeFd $fd $count $host
} else {
set buf [gets $fd]
.text insert {end} "$buf\n"
}
}
proc closeFd {fd count host} {
close $fd
.btn configure -text {Clink to start ping} -command "RunPing $host $count"
}
为了使用同样条件的管道,屏蔽了设置非阻塞的代码行,但这么作
因为系统不得不等待管道中的进程运行结束,所以
也使得
close
没有起到应有的作用。
运行的结果很令人满意,
test
没有被阻塞,在显示
ping
结果的同时,依然可以在
text
中执行输入,而且
button
也可以被顺利按下。这么看来
Tcl/Tk
比之
Perl
在
win32
下,显然在事件处理上占有优势,而且这个占优的方面是极其重要的。