2016-06-25 1 views
3

Я пытаюсь эмулировать синхронный поток управления в асинхронной среде.Можно ли сделать что-то вроде longjump в Perl внутри EV-обратных вызовов?

Целью является поддержка запросов БД без обратных вызовов или блокировки по запросу.

Я пытаюсь использовать модуль Coro, но я думаю, что не понимаю его полностью.

Вот фрагменты кода:

sub execute { 
    my ($sth, @vars) = @_; 

    my $res = $sth->SUPER::execute(@vars); 
    my $dbh = $sth->{Database}; 
    my $async = new Coro::State; 
    my $new; 
    $new = new Coro::State sub { 
     my $w; 
     while (!$dbh->pg_ready) { 
      $w = AnyEvent->io(
       fh => $dbh->{pg_socket}, 
       poll => 'r', 
       cb => sub { 
        if($dbh->pg_ready) { 
         $w = undef; 
         $new->transfer($async); 
        } 
       } 
      ) if not $w; 
      print "run once before statement: $sth->{Statement}\n"; 
      EV::run EV::RUN_ONCE; 
     } 
    }; 
    $async->transfer($new); 
    $res = $dbh->pg_result; 
    $res; 
} 

Вот код тестирования:

my $cv = AE::cv; 

ok(my $dbh = db_connect(), 'connected'); 
ok(my $sth = $dbh->prepare('select pg_sleep(2)'), 'prepared'); 

my $start_time = time; 
ok($sth->execute(), 'executed'); 

my $duration = time - $start_time; 
ok(($duration > 1 && $duration < 3), 'slept'); 
is(ref($dbh), 'DBIx::PgCoroAnyEvent::db', 'dbh class'); 
is(ref($sth), 'DBIx::PgCoroAnyEvent::st', 'sth class'); 

my $status = 0; 
my $finished = 0; 

for my $t (1 .. 10) { 
    $finished += 1 << $t; 
} 

for my $t (1 .. 10) { 

    my $timer; 

    $timer = AE::timer 0.01 + $t/100, 0, sub { 

     ok(my $dbh = db_connect(), "connected $t"); 
     ok(my $sth = $dbh->prepare('select pg_sleep(' . $t . ')'), "prepared $t"); 
     my $start_time = time; 
     ok($sth->execute(), "executed $t"); 

     my $duration = time - $start_time; 
     ok(($duration > $t - 1 && $duration < $t + 1), "slept $t"); 

     print "duration: $t: $duration\n"; 

     $status += 1 << $t; 
     if ($status == $finished) { 
      $cv->send; 
     } 

     undef $timer; 
    }; 
} 

$cv->recv; 

Полный модуль и тестовые скрипты здесь DBIx::PgCoroAnyEvent и здесь 01_sleeps.t

Может кто-нибудь взглянуть и объясните мне, что там не так?

+0

[Return :: MultiLevel] (https://metacpan.org/pod/Return::MultiLevel) вроде как longjmp, но я ничего не знаю о Коро или, как они будут взаимодействовать. – melpomene

+0

Return :: MultiLevel не отвечает моим потребностям. Сожалею. –

+3

Это не связано с вашим вопросом, но вам следует избегать 'undef $ timer', поскольку он заставляет цикл сбора мусора, и Perl обычно намного лучше знает, когда он должен освобождать память, чем вы. Если вы хотите де-инициализировать переменную, напишите '$ timer = undef'. Кроме того, в этом случае '$ timer' выходит за пределы области видимости и в конце каждой итерации цикла' for' уничтожается, поэтому нет смысла изменять его значение. – Borodin

ответ

0

eval + die - типичный метод в Perl.

eval { some_function(@args); }; 
if([email protected]){ 
    # caught longjmp 
} 
... 
sub some_function { 
    ... 
    if(some_condition){ 
     die "throw longjmp" 
    } 
    ... 
} 
+0

Нет. Вы не смотрите на код. –

Смежные вопросы