【发布时间】:2019-06-04 16:03:05
【问题描述】:
我们已经有一个使用 AnyEvent 的库。它在内部使用 AnyEvent 并最终返回一个值(同步 - 不使用回调)。有什么办法可以将这个库与 Mojolicious 一起使用?
它做了类似的事情:
#!/usr/bin/perl
use strict;
use warnings;
use AnyEvent;
use Mojolicious::Lite;
# To the caller, getData is a synchronous sub that returns a value.
# The fact that it uses AnyEvent is an internal implementation detail of
# getData
sub getData {
my $cv = AnyEvent->condvar;
my $w = AnyEvent->timer (after => 5, cb => sub {
# Perform many async operations, represented here by a single timer,
# calculating a final result that is sent:
$cv->send(42);
});
my $result = $cv->recv;
# postProcess($result);
return $result;
}
get '/' => sub {
my ($c) = @_;
$c->render(text => "Data is: " . getData());
};
app->start;
当我同时从两个浏览器选项卡运行 morbo app.pl 并尝试 get '/' 时,我收到此错误:
AnyEvent::CondVar: recursive blocking wait attempted at /bla/bla/app.pl line 16.
我认为发生的事情是 morbo 在内部使用 EV,因此当它调度处理第一个 get '/' 时,$cv->recv 最终被调用,返回到 EV 事件循环。 EV 现在尝试处理第二个get '/' 并再次调用$cv->resv,从而触发错误。
我知道我可以从getData() 中重构$cv 以制作异步版本,但实际上真正的“getData”在很多地方都被调用,并且将所有对“getData”的调用转换为异步代码是不可行的.
所以我的问题是:有什么方法可以在使用morbo/Mojolicious 时可靠地调用上面的确切getData()?我希望 get '/' 在完成之前阻止。
编辑: AnyEvent 的 WHAT TO DO IN A MODULE 部分明确表示:
永远不要在条件变量上调用 ->recv,除非你知道已经调用了 ->send 方法。这是因为它会使整个程序停顿,而使用事件的全部意义在于保持交互性。
getData() 以上违反了这一点。现在我明白了 AnyEvent 文档那部分的原因:-)
【问题讨论】:
标签: perl mojolicious anyevent