3

I am trying to emulate synchronous control flow in an asynchronous environment.

The purpose is to support DB requests without callbacks or blocking on request.

I am trying to use the Coro module, but I think I don't understand it in full.

Here are the code snippets:

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

Here is the testing code:

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;

Full module and test scripts are here DBIx::PgCoroAnyEvent and here 01_sleeps.t

Can someone have a look and explain me what is wrong there?

  • [Return::MultiLevel](https://metacpan.org/pod/Return::MultiLevel) is sort of like longjmp but I know nothing about Coro or how they would interact. – melpomene Jun 25 '16 at 13:22
  • Return::MultiLevel doesn't pass my needs. Sorry. – Anton Petrusevich Jun 25 '16 at 14:13
  • 3
    This is unrelated to your question, but you should avoid `undef $timer` as it forces a garbage-collection cycle, and Perl is usually much better at knowing when it should free memory than you are. If you want to de-initialise a variable then write `$timer = undef`. Also, in this case, `$timer` goes out of scope and gets destroyed at the end of each iteration of the `for` loop anyway, so there's no point in changing its value. – Borodin Jun 25 '16 at 16:56
  • 1
    @Borodin Perl has no garbage collection cycles. – melpomene Jun 25 '16 at 18:29
  • @melpomene: It releases the memory for re-use. What would you prefer to call it? – Borodin Jun 25 '16 at 18:54
  • @Borodin Well, it calls `free()`. I don't think that's comparable to garbage collection. – melpomene Jun 25 '16 at 19:23
  • 1
    @melpomene: It's doesn't call `free`, it retains the memory for its own use but deallocates it from the variable, and it's generally better not to force that to happen, otherwise you'll get into a deallocate/reallocate cycle which is wasteful – Borodin Jun 25 '16 at 19:29
  • I believe there's no difference between `undef $var` and `$var = undef`. – Anton Petrusevich Jun 25 '16 at 21:44
  • 2
    @Anton Petrusevich, `undef $var;` is different than `$var = undef;`. The latter doesn't free any memory, making future use of the variable more efficient. It doesn't matter here (even though the same var is used for each loop pass, because it never contains anything other than undef or a reference), but using `undef $var;` is a bad habit. – ikegami Jun 26 '16 at 02:31
  • @Anton Petrusevich, What output are you getting? What problem are you having? – ikegami Jun 26 '16 at 02:42
  • @Anton Petrusevich, `perl -MDevel::Size=total_size -E'$x = "x"x20; say total_size($x); $x=undef; say total_size($x); undef $x; say total_size($x);'` prints 54, 54, 32 (exact numbers may vary). Notice that doing `$var=undef` did not change the size, while `undef $var;` did? – ikegami Jun 26 '16 at 17:01
  • @ikegami Try [this](http://pastebin.com/BCAPcuPy). It clearly shows than I am right – Anton Petrusevich Jun 26 '16 at 17:10
  • @Anton Petrusevich, Stop trying to prove there's no difference after I showed there is one. The fact that *you* can't find one doesn't indicate there isn't one. – ikegami Jun 26 '16 at 17:10
  • @ikegami have you tried? – Anton Petrusevich Jun 26 '16 at 17:12
  • @Anton Petrusevich, Yes, but it only demonstrates that *you* couldn't find a difference even though there is one. Did you try mine? – ikegami Jun 26 '16 at 17:13
  • You are allocating scalar, it can be different due to some optimizations. – Anton Petrusevich Jun 26 '16 at 17:15
  • It is. `undef $var;` specifically disables optimizations. That's why you shouldn't use it. – ikegami Jun 26 '16 at 17:16
  • @ikegami have _you_ found difference in my prorgam? – Anton Petrusevich Jun 26 '16 at 17:17
  • There is no difference in your program. I already said that yesterday. ("*It doesn't matter here, but using `undef $var;` is a bad habit.*") – ikegami Jun 26 '16 at 17:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/115652/discussion-between-anton-petrusevich-and-ikegami). – Anton Petrusevich Jun 26 '16 at 17:19
  • I changed code in execute(), nothing changed. I get failing tests and then coredump. perl 5.20.3 and coro 6.51. – Anton Petrusevich Jun 27 '16 at 13:38
  • @ikegami here is the [output](https://gist.github.com/jef-sure/a55696b3f495ee5d590456d3145c6459) – Anton Petrusevich Jun 27 '16 at 15:49
  • Don't spread your question over 4 pages, and leave out anything that's not necessary. Version of Coro and Perl are also obviously relevant here, so they should be provided. Coro 6.5 seems to be in flux (since another version was released since we last talked), so your testing needs to be performed with Perl 5.20 (or earlier) and Coro 6.49. – ikegami Jun 27 '16 at 16:16

1 Answers1

0

eval+die is the typical method in Perl.

eval { some_function( @args ); };
if( $@ ){
    # caught longjmp
}
...
sub some_function {
    ...
    if( some_condition ){
        die "throw longjmp"
    }
    ...
}
shawnhcorey
  • 3,545
  • 1
  • 15
  • 17