perl中不同线程中全局数组的使用
Use of global arrays in different threads in perl
在不同线程中使用全局数组
我将使用 Dancer2 和 File::Tail 在网络上使用 Tail。因此,当 Websocket 打开时,它将 $conn 存储在一个数组中,当检测到 File::Tail 时,它会尝试将数据发送到存储在数组中的套接字。但它并没有像预期的那样工作。
发生websocket连接时保存的数组可能不是全局变量。
# it doesn't works.
foreach (@webs) {
$_->send_utf8("test2!!!!!!!!");
}
我尝试使用 threads::shared 和 Cache::Memcached 等,但我失败了。
我不太了解perl。自己尝试解决了,但是太久没解决,所以留个问题。
这是完整的代码。
use File::Tail ();
use threads;
use threads::shared;
use Net::WebSocket::Server;
use strict;
use Dancer2;
my @webs = ();
# my %clients :shared = ();
my $conns :shared = 4;
threads->create(sub {
print "start-end:", "$conns", "\n";
my @files = glob( $ARGV[0] . '/*' );
my @fs = ();
foreach my $fileName(@files) {
my $file = File::Tail->new(name=>"$fileName",
tail => 1000,
maxinterval=>1,
interval=>1,
adjustafter=>5,resetafter=>1,
ignore_nonexistant=>1,
maxbuf=>32768);
push(@fs, $file);
}
do {
my $timeout = 1;
(my $nfound,my $timeleft,my @pending)=
File::Tail::select(undef,undef,undef,$timeout,@fs);
unless ($nfound) {
} else {
foreach (@pending) {
my $str = $_->read;
print $_->{"input"} . " ||||||||| ".localtime(time)." ||||||||| ".$str;
# it doesn't works.
foreach (@webs) {
$_->send_utf8("test!!!!!!!!");
}
}
}
} until(0);
})->detach();
threads->create(sub {
Net::WebSocket::Server->new(
listen => 8080,
on_connect => sub {
my ($serv, $conn) = @_;
push(@webs, $conn);
$conn->on(
utf8 => sub {
my ($conn, $msg) = @_;
$conn->send_utf8($msg);
# it works.
foreach (@webs) {
$_->send_utf8("test!!!!!!!!");
}
},
);
},
)->start;
})->detach();
get '/' => sub {
my $ws_url = "ws://127.0.0.1:8080/";
return <<"END";
<html>
<head><script>
var urlMySocket = "$ws_url";
var mySocket = new WebSocket(urlMySocket);
mySocket.onmessage = function (evt) {
console.log( "Got message " + evt.data );
};
mySocket.onopen = function(evt) {
console.log("opening");
setTimeout( function() {
mySocket.send('hello'); }, 2000 );
};
</script></head>
<body><h1>WebSocket client</h1></body>
</html>
END
};
dance;
perl 中的线程不是轻量级的。它们是程序的独立实例。
线程唯一的共同点是在线程实例化之前就存在的东西。
您可以 - 通过声明共享变量 - 允许数据结构在线程之间共享,但是我警告您在这里要小心 - 如果没有某种方式的锁定,您可能会为自己创造竞争条件。
在您的情况下,您可以将@webs
声明为: shared
。这意味着插入其中的值对所有线程都是可见的。但是你仍然需要一定程度的谨慎,因为 'when stuff is added' 仍然是不确定的。
但无论如何,这基本上有效:
#!/usr/bin/env perl
use strict;
use warnings;
use threads;
use threads::shared;
use Data::Dumper;
my @shared_struct : shared;
sub reader {
print "Starting reader\n";
for ( 1..10 ) {
print threads -> self() -> tid(), ":", join (",", @shared_struct ), "\n";
sleep 1;
}
}
sub writer {
print "starting writer\n";
for ( 1..10 ) {
push @shared_struct, rand(10);
print Dumper \@shared_struct;
sleep 1;
}
}
## start the threads;
my $reader = threads -> create ( \&reader );
my $writer = threads -> create ( \&writer );
while ( 1 ) {
print @shared_struct;
sleep 1;
}
更一般地说,我建议您几乎从不真正想要在 perl 中分离线程 - 这样做,您的意思是“我不关心您的执行”。很明显,您的代码并非如此 - 您正在尝试与线程对话。
只需创建线程即可完成您想要的 - 并行执行,您可以:
for my $thread ( threads -> list ) {
$thread -> join;
}
当您准备好线程终止时。
在不同线程中使用全局数组
我将使用 Dancer2 和 File::Tail 在网络上使用 Tail。因此,当 Websocket 打开时,它将 $conn 存储在一个数组中,当检测到 File::Tail 时,它会尝试将数据发送到存储在数组中的套接字。但它并没有像预期的那样工作。
发生websocket连接时保存的数组可能不是全局变量。
# it doesn't works.
foreach (@webs) {
$_->send_utf8("test2!!!!!!!!");
}
我尝试使用 threads::shared 和 Cache::Memcached 等,但我失败了。
我不太了解perl。自己尝试解决了,但是太久没解决,所以留个问题。
这是完整的代码。
use File::Tail ();
use threads;
use threads::shared;
use Net::WebSocket::Server;
use strict;
use Dancer2;
my @webs = ();
# my %clients :shared = ();
my $conns :shared = 4;
threads->create(sub {
print "start-end:", "$conns", "\n";
my @files = glob( $ARGV[0] . '/*' );
my @fs = ();
foreach my $fileName(@files) {
my $file = File::Tail->new(name=>"$fileName",
tail => 1000,
maxinterval=>1,
interval=>1,
adjustafter=>5,resetafter=>1,
ignore_nonexistant=>1,
maxbuf=>32768);
push(@fs, $file);
}
do {
my $timeout = 1;
(my $nfound,my $timeleft,my @pending)=
File::Tail::select(undef,undef,undef,$timeout,@fs);
unless ($nfound) {
} else {
foreach (@pending) {
my $str = $_->read;
print $_->{"input"} . " ||||||||| ".localtime(time)." ||||||||| ".$str;
# it doesn't works.
foreach (@webs) {
$_->send_utf8("test!!!!!!!!");
}
}
}
} until(0);
})->detach();
threads->create(sub {
Net::WebSocket::Server->new(
listen => 8080,
on_connect => sub {
my ($serv, $conn) = @_;
push(@webs, $conn);
$conn->on(
utf8 => sub {
my ($conn, $msg) = @_;
$conn->send_utf8($msg);
# it works.
foreach (@webs) {
$_->send_utf8("test!!!!!!!!");
}
},
);
},
)->start;
})->detach();
get '/' => sub {
my $ws_url = "ws://127.0.0.1:8080/";
return <<"END";
<html>
<head><script>
var urlMySocket = "$ws_url";
var mySocket = new WebSocket(urlMySocket);
mySocket.onmessage = function (evt) {
console.log( "Got message " + evt.data );
};
mySocket.onopen = function(evt) {
console.log("opening");
setTimeout( function() {
mySocket.send('hello'); }, 2000 );
};
</script></head>
<body><h1>WebSocket client</h1></body>
</html>
END
};
dance;
perl 中的线程不是轻量级的。它们是程序的独立实例。
线程唯一的共同点是在线程实例化之前就存在的东西。
您可以 - 通过声明共享变量 - 允许数据结构在线程之间共享,但是我警告您在这里要小心 - 如果没有某种方式的锁定,您可能会为自己创造竞争条件。
在您的情况下,您可以将@webs
声明为: shared
。这意味着插入其中的值对所有线程都是可见的。但是你仍然需要一定程度的谨慎,因为 'when stuff is added' 仍然是不确定的。
但无论如何,这基本上有效:
#!/usr/bin/env perl
use strict;
use warnings;
use threads;
use threads::shared;
use Data::Dumper;
my @shared_struct : shared;
sub reader {
print "Starting reader\n";
for ( 1..10 ) {
print threads -> self() -> tid(), ":", join (",", @shared_struct ), "\n";
sleep 1;
}
}
sub writer {
print "starting writer\n";
for ( 1..10 ) {
push @shared_struct, rand(10);
print Dumper \@shared_struct;
sleep 1;
}
}
## start the threads;
my $reader = threads -> create ( \&reader );
my $writer = threads -> create ( \&writer );
while ( 1 ) {
print @shared_struct;
sleep 1;
}
更一般地说,我建议您几乎从不真正想要在 perl 中分离线程 - 这样做,您的意思是“我不关心您的执行”。很明显,您的代码并非如此 - 您正在尝试与线程对话。
只需创建线程即可完成您想要的 - 并行执行,您可以:
for my $thread ( threads -> list ) {
$thread -> join;
}
当您准备好线程终止时。