我们已经有一个使用 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 ,因此当它调度处理 firstget '/'
时,$cv->recv
最终被调用,返回到 EV 事件循环。EV 现在尝试处理第二个get '/'
并$cv->resv
再次被调用,从而触发错误。
我知道我可以重构$cv
out ofgetData()
以制作异步版本,但实际上真正的“getData”在许多地方被调用,并且将所有对“getData”的调用转换为异步代码是不可行的。
所以我的问题是:有什么方法可以getData()
在使用morbo
/Mojolicious 时可靠地调用上面的内容?我想get '/'
阻止,直到它完成。
编辑: AnyEvent 的在模块中做什么部分明确地说:
永远不要在条件变量上调用 ->recv,除非你知道已经调用了 ->send 方法。这是因为它会停止整个程序,而使用事件的全部意义在于保持交互。
getData()
以上违反了这一点。现在我明白了 AnyEvent 文档那部分的原因:-)