基于AnyEvent :: Socket工作的代码不稳定

时间:2014-04-22 14:51:47

标签: perl anyevent

我使用AnyEvent(用于研究)创建memcached客户端并实现以下代码:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use feature 'say';
    use Carp qw/croak carp/;

    use AnyEvent;
    use AnyEvent::Handle;
    use AnyEvent::Socket;
    use EV;

    sub get {
      my ($host, $port, $cv, $keys, %args) = @_; # $args -> cb => sub {$value, $err}

      $cv->begin if $cv;

      tcp_connect $host => $port, sub {
        my $fh = shift or die "unable to connect: $!";

        my $handle;
        $handle = new AnyEvent::Handle
          fh => $fh,
          on_error => sub {
            my ($handler, $fatal, $msg) = @_;
            AE::log error => $msg;
            $handler->destroy;
            $cv->send;
          },
          on_eof => sub {
            $handle->destroy; # destroy handle
            AE::log info => "Done.";
            $cv->send;
          };

          my $array = 1 if ref $keys and ref $keys eq 'ARRAY';
          my $key = $array
            ? 'get ' . join(' ', @$keys) . "\r\n"
            : "get $keys\r\n";

          $cv->begin;
          $handle->push_write($key);

          my $result;

          my $reader; $reader = sub {
             my ($handle, $line) = @_;

              if ($line eq 'END') {
                undef $reader;
                $args{cb}($result);
              }
              elsif (substr($line, 0, 5) eq 'ERROR') {
                undef $reader;
                $args{cb}(undef, $line);
              }
              elsif (!length($line)) {
                warn "Skip empty line";
                $handle->unshift_read(line => $reader);
              }
              elsif($line =~ /^VALUE (\S+) (\d+) (\d+)(?:| (.+))$/ ) {
                my ($key, $flags, $len, $cas) = ($1, $2, $3, $4);
                $handle->push_read(chunk => $len+2, sub { # data length + \r\n
                  my ($handle, $data) = @_;
                  substr($data, $len) = ''; # trim \r\n
                  if ($array) {
                    $result->{$key} = $data;
                  } else {
                    $result = $data;
                  }
                  $handle->unshift_read(line => $reader);
                  $cv->send;
                });
            }
          };

        $handle->push_read(line => $reader);
        $cv->end;
    }, sub { 30; };
    }

    my $cv = AnyEvent->condvar;

    my $host = '127.0.0.1';
    my $port = 11211;

    get($host, $port, $cv, 'data', cb => sub {
    my ($value, $err) = @_;
    $err and return warn "Get failed: @_";
    warn "Value for key is '$value'";
  });

get($host, $port, $cv, [qw/data someKey/], cb => sub {
    my ($values, $err)  = @_;
    $err and return warn "Get failed: @_";
    warn "Value for key1 is '$values->{data}' and value for key2 is '$values->{someKey}'";
  });

$cv->recv;

但由于某些原因,这段代码不稳定。输出:

$ perl test_anyevent.pl 
 Value for key1 is 'hello memcached world' and value for key2 is 'hello world' at test_anyevent.pl line 95.
 Value for key is 'hello memcached world' at test_anyevent.pl line 89.
 $ perl test_anyevent.pl 
 Value for key1 is 'hello memcached world' and value for key2 is 'hello world' at test_anyevent.pl line 95.
 $ perl test_anyevent.pl 
 Value for key1 is 'hello memcached world' and value for key2 is 'hello world' at test_anyevent.pl line 95.
 Value for key is 'hello memcached world' at test_anyevent.pl line 89.
 $ perl test_anyevent.pl 
 Value for key1 is 'hello memcached world' and value for key2 is 'hello world' at test_anyevent.pl line 95.
 Value for key is 'hello memcached world' at test_anyevent.pl line 89.

我不知道为什么'得'命令一个工作,然后两个。如果我使用模块AnyEvent :: Memcached,那么一切都很好:

#!/usr/bin/perl -w
use strict;
use warnings;
use feature 'say';

use AnyEvent;
use EV;
use AnyEvent::Memcached;

my $cv = AnyEvent->condvar;

my $memd = AnyEvent::Memcached->new(
  servers => ['127.0.0.1:11211'],
  cv => $cv,
);

$memd->get('data', cb => sub {
    my ($value, $err) = shift;
    $err and return warn "Get failed: @_";
    warn "Value for key is $value";
  });

$memd->get([qw/data someKey/], cb => sub {
    my ($values, $err)  = shift;
    $err and return warn "Get failed: @_";
    warn "Value for key1 is '$values->{data}' and value for key2 is '$values->{someKey}'";
  });

$cv->recv;

输出:

$ perl anyevent_memcached_mons.pl 
 Value for key is hello memcached world at anyevent_memcached_mons.pl line 20.
 Value for key1 is 'hello memcached world' and value for key2 is 'hello world' at anyevent_memcached_mons.pl line 26.
 $ perl anyevent_memcached_mons.pl 
 Value for key is hello memcached world at anyevent_memcached_mons.pl line 20.
 Value for key1 is 'hello memcached world' and value for key2 is 'hello world' at anyevent_memcached_mons.pl line 26.
 $ perl anyevent_memcached_mons.pl 
 Value for key is hello memcached world at anyevent_memcached_mons.pl line 20.
 Value for key1 is 'hello memcached world' and value for key2 is 'hello world' at anyevent_memcached_mons.pl line 26.

无法理解可能出现什么问题?

0 个答案:

没有答案