gpt4 book ai didi

perl - 避免 Mojolicious 异步行为?避免 "AnyEvent::CondVar: recursive blocking wait attempted"

转载 作者:行者123 更新时间:2023-12-03 05:31:48 28 4
gpt4 key购买 nike

我们已经有一个使用 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 并尝试同时从两个浏览器选项卡获取“/”时,我收到此错误:

AnyEvent::CondVar: recursive blocking wait attempted at /bla/bla/app.pl line 16.

我认为发生的事情是 morbo 在内部使用 EV,因此当它分派(dispatch)处理第一个 get '/' 时,$cv->recv 最终结束被调用,返回到 EV 事件循环。 EV 现在尝试处理第二个 get '/' 并再次调用 $cv->resv,从而触发错误。

我知道我可以重构 getData() 中的 $cv 来制作异步版本,但实际上,真正的“getData”在很多地方被调用,并且将所有对“getData”的调用转变为异步代码是不可行的。

所以我的问题是:在使用 morbo/Mojolicious 时,有什么方法可以可靠地调用上面的确切 getData() 吗?我希望 get '/' 阻止直到完成。

编辑: AnyEvent 的 WHAT TO DO IN A MODULE部分明确表示:

Never call ->recv on a condition variable unless you know that the ->send method has been called on it already. This is because it will stall the whole program, and the whole point of using events is to stay interactive.

上面的

getData() 违反了这一点。现在我明白了 AnyEvent 文档那部分的原因:-)

最佳答案

您可以通过确保 Mojolicious 和 AnyEvent 不使用相同的主循环来避免此问题,方法是设置环境变量 MOJO_REACTOR=Mojo::Reactor::Poll 或使用 AnyEvent::Loop在其他任何事情之前,以便 AnyEvent 使用其纯 Perl 循环(首选,因为它不被用作主循环)。不幸的是,没有办法让它使用单独实例化的循环,否则如何 Mojo::UserAgent blocking requests功能。

请注意,通常情况下,您希望多个循环使用者共享主循环;这是一个奇怪的情况,您希望阻止内部消费者。

<小时/>

一个更“异步”的长期解决方案可能是简单地允许操作共享主循环,因为 Mojolicious 是为非阻塞响应操作而设计的。您可以通过首先确保两者实际上共享 EV 主循环(例如通过设置 MOJO_REACTOR=Mojo::Reactor::EV ),然后更改您的函数或创建新版本来实现此目的函数的,返回 promise该函数将异步填充结果,并将依赖该结果的任何进一步功能链接到该 promise 之外。当然,您的函数比您在此处使用的单个计时器更复杂,但它仍然值得考虑 - 它将允许应用程序在等待 AnyEvent 操作结果的同时继续服务其他请求。

sub getData_p {
my $p = Mojo::Promise->new;
my $w; # keep a strong reference to $w for AnyEvent's reasons
$w = AnyEvent->timer(after => 5, cb => sub { $p->done(42); undef $w });
return $p;
}

get '/' => sub {
my ($c) = @_;
my $tx = $c->render_later->tx; # keep strong reference to $tx
getData_p()->then(sub { $c->render(text => "Data is: $_[0]") })
->catch(sub { $c->reply->exception($_[0]); undef $tx });
};

关于perl - 避免 Mojolicious 异步行为?避免 "AnyEvent::CondVar: recursive blocking wait attempted",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56447536/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com