【问题标题】:Sequentioal requests with Mojo::IOLoop::DelayMojo::IOLoop::Delay 的顺序请求
【发布时间】:2017-10-07 11:19:33
【问题描述】:

我需要在非阻塞模式下获取 URL 列表,但不是并行。它应该是一个接一个的顺序请求。我怎么能意识到这一点?

我找不到示例。文档和文章仅强调并行执行。

现在我的代码如下所示(简化):

my $delay = Mojo::IOLoop::Delay->new;

$delay->steps(
    sub {
        build_report();
        say "done";
    }
);

sub parse_data {
    ...;
    my $url = shift @urls;
    my $end = $delay->begin;
    $ua->get( $url => \&parse_data );
    $end->();
}

my $end = $delay->begin;
$ua->get( $url => \&parse_data );
$end->();
$delay->wait;

我想通过使用Mojo::IOLoop::Delay 来避免多次关闭。

【问题讨论】:

  • 什么是$uabuild_report 是做什么的?
  • $ua 是 Mojo::UserAgent; build_report 在摘要报告中收集所有请求的数据。

标签: perl asynchronous mojolicious


【解决方案1】:

我刚刚开始为自己的项目寻找Mojo::IOLoop,但我还不知道它。但我认为最简单的方法是构建一个闭包数组并将其传递给$delay->steps

use strict;
use warnings 'all';
use feature 'say';

use Mojo;

use constant URL => 'http://stackoverflow.com/questions/tagged/perl';

STDOUT->autoflush;

my $ua = Mojo::UserAgent->new;
my $delay = Mojo::IOLoop::Delay->new;

my @urls = ( URL ) x 10;

my @steps =  map {

    my $url = $_;

    sub {

        my $end = $delay->begin;

        $ua->get( $url => sub {
            my ( $ua, $txn ) = @_;

            $end->();

            if ( my $err = $txn->error ) {
                say $err->message;
            }
            else {
                my $res = $txn->success;
                say "@{$res}{qw/ code message /}";
            }
        });
    }

} @urls;


$delay->steps( @steps, sub { say 'Done' } );

Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

输出

200 OK
200 OK
200 OK
200 OK
200 OK
200 OK
200 OK
200 OK
200 OK
Done
200 OK

注意Done 打印在最终get 的状态行之前,因为我在回调到达时立即调用了$end->(),假设不需要同步任何响应处理

如果您不想这样,只需将$end->() 移动到回调的末尾即可。然后延迟会等到输出产生后再发送另一个请求

【讨论】:

  • 谢谢,正是我需要的!
【解决方案2】:

顺序请求非常容易实现。

网络服务器

#!/usr/bin/perl
use Mojo::Base -strict;

use Mojolicious::Lite;

get '/' => sub {
  my $c = shift->render_later;

  $c->delay(sub {
    my $delay = shift;
    $c->ua->get('https://google.ru' => $delay->begin);
  }, sub {
    my ($delay, $tx) = @_;
    $tx->res->body; # body of the google.ru
    $c->ua->get('https://twitter.com' => $delay->begin);
  }, sub {
    my ($delay, $tx) = @_;
    $tx->res->body; # body of the twitter.com
    $c->render(text => 'Done');
  });
};

app->start;

脚本

#!/usr/bin/perl
use Mojo::Base -strict;

use Mojo::IOLoop;
use Mojo::UserAgent;

my $ua = Mojo::UserAgent->new;

Mojo::IOLoop->delay(sub {
  my $delay = shift;
  $ua->get('https://www.google.ru' => $delay->begin);
}, sub {
  my ($delay, $tx) = @_;
  $tx->res->body; # body of the google.ru
  $ua->get('https://twitter.com' => $delay->begin);
}, sub {
  my ($delay, $tx) = @_;
  $tx->res->body; # body of the twitter.com
  warn 'DONE';
})->wait;

脚本(动态请求)

Example here

【讨论】:

  • 没关系,但不知道列表中有多少个URL。我必须在 delay() 中动态添加潜艇。我找不到怎么做。
  • 我更新帖子以添加示例,但我认为如果您立即关闭,代码可能看起来更漂亮。
  • 我必须使用延迟,因为它是网络服务器,它应该立即返回答案。所以,它应该是异步获取。您在链接下的示例与我的代码相同。我不喜欢它。
  • 延迟不允许您立即执行请求。延迟需要按顺序写代码。所以你需要简单地移除延迟,因为没有它的代码看起来更清晰。我更新了我的要点以添加 2 个示例:没有延迟,另一个有延迟。再次点击示例!
  • callback.dynamic.sequential.pl 看起来很漂亮,但是我应该将最终函数 build_report() 放在哪里?它应该将所有请求汇总到一个订单中。
猜你喜欢
  • 2018-06-08
  • 2016-08-08
  • 2016-03-22
  • 2018-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多