Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 如何从回调调用事件循环?_Perl_Event Loop_Anyevent - Fatal编程技术网

Perl 如何从回调调用事件循环?

Perl 如何从回调调用事件循环?,perl,event-loop,anyevent,Perl,Event Loop,Anyevent,也就是说,让事件循环处理队列中当前的事件。在VBA中,调用名为DoEvents 我想用Perl来做这件事。无论如何最好这样做,因为我用它写了一个脚本。但我在文档中找不到任何类似的函数 我天真地尝试用condvar实现它,因为文档中说,recv调用事件循环,但失败了,下面是示例代码: use strict; use warnings; use AnyEvent; use AnyEvent::Strict; sub _long_task; my $t1 = AE::timer 0, 3, su

也就是说,让事件循环处理队列中当前的事件。在VBA中,调用名为
DoEvents

我想用Perl来做这件事。无论如何最好这样做,因为我用它写了一个脚本。但我在文档中找不到任何类似的函数

我天真地尝试用condvar实现它,因为文档中说,
recv
调用事件循环,但失败了,下面是示例代码:

use strict;
use warnings;

use AnyEvent;
use AnyEvent::Strict;

sub _long_task;

my $t1 = AE::timer 0, 3, sub{print"task 1, with interval 3 seconds\n";};
my $t2 = AE::timer 0, 7, sub{print"task 2, with interval 7 seconds\n";};
my $t3 = AE::timer 0, 11, sub{print"task 3, with interval 11 seconds\n";};
my $t_long = AE::timer 0, 0, \&_long_task;

sub DoEvents()
{
    my $cv = AE::cv;
    my $t = AE::timer 0, 0, sub { $cv->send; };
    $cv->recv;
}

sub _long_task {
    print"long task: ENTERING\n";
    for(1..5) {
        print"long task: doing some work for 2 seconds\n";
        sleep 2;
        print"long task: calling DoEvents\n";
        DoEvents();
    }
    print"long task: EXITING, resheduling after 10 seconds\n";
    $t_long = AE::timer 10, 0, \&_long_task;
}

AE::cv->recv;
输出为:

task 1, with interval 3 seconds
task 2, with interval 7 seconds
task 3, with interval 11 seconds
long task: ENTERING
long task: doing some work for 2 seconds
long task: calling DoEvents
AnyEvent::CondVar: recursive blocking wait attempted at C:\Users\andreyi\Desktop\try_event_loop.pl line 18.
更新: AnyEvent.pm中有行:

  $WAITING
     and Carp::croak "AnyEvent::CondVar: recursive blocking wait attempted";
如果您对它们进行注释,DoEvents()将起作用


但是,最好有一个不涉及此CPAN模块的管理的解决方案。

每个问题都至少有一个简单的解决方案(有时是一个肮脏的黑客)

在我的情况下,这个似乎有效。我将其添加到生产代码中

BEGIN { our $orig_Carp_croak = \&Carp::croak; }
sub DoEvents()
{
    my $cv = AE::cv;
    my $t = AE::timer 0, 0, $cv;
    no warnings 'redefine';
    local *Carp::croak = sub{
        (caller 1)[3] eq 'AnyEvent::CondVar::Base::recv'
            && $_[0] =~ /recursive blocking wait attempted/
            && return;
        goto \&{our $orig_Carp_croak};
    };
    $cv->recv;
}
更新: 对于所有调用DoEvents的回调,您需要确保它们没有重新输入。像这样:

our $entered_callbacks = {};
# ...
sub some_callback {
    $entered_callbacks->{some_callback} && return;
    local $entered_callbacks->{some_callback} = 1;
    ...;
}

循环EV和AnyEvent::Loop有一个缺陷,即回调只有在返回时才从队列中删除,而不是在调用之前。它使事件循环对于再入来说不安全。

我想你需要Coro,一个可以与任何事件一起工作的合作性多任务系统。更改
my$t_long=AE::计时器0、0、\&_long_任务
异步{u long_task()}
并将
DoEvents()
更改为
cede()
。顺便说一句,
$cv
用作回调时相当于
sub{$cv->send;}
。问题是您在回调内部阻塞了。。。这也不起作用:(忘了提及:不要在AnyEvent.pm中评论这些行。它们正确地检测到了问题。