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; 
}

当您准备好线程终止时。