如何在perl plack应用程序中实现非阻塞响应?

时间:2014-07-09 13:12:31

标签: perl nonblocking plack anyevent

我正在尝试使用Twiggy::Server(这意味着一个plack应用程序)编写一个基于perl的网络服务器。 我想通过运行一些可能耗时的子程序来响应某些数据的请求(来自网页上的ajax调用),该子程序生成数据然后将其转换为JSON字符串以返回客户端网页。

您可以在此处查看我的服务器的缩减测试版:http://pastebin.com/iNaDTVwL 这个例子显示了我当前实现的问题;使用AnyEvent::ForkManager执行非阻塞部分会导致截断“大'json响应。

本文档将完美地回答我的问题(并更好地解释我正在尝试做的事情):https://github.com/jjn1056/Example-PlackStreamingAndNonblocking ......如果它已经完成。我只是错过了进行非阻塞的“正确”方式,而不是使用AnyEvent::ForkManager这似乎有点像黑客。

2 个答案:

答案 0 :(得分:1)

我个人使用Net::Async::HTTP::Server::PSGI。从其概要:

use Net::Async::HTTP::Server::PSGI;
use IO::Async::Loop;

my $loop = IO::Async::Loop->new;

my $httpserver = Net::Async::HTTP::Server::PSGI->new(
   app => sub {
      my $env = shift;

      return [
         200,
         [ "Content-Type" => "text/plain" ],
         [ "Hello, world!" ],
      ];
   },
);

$loop->add( $httpserver );

$httpserver->listen(
   addr => { family => "inet6", socktype => "stream", port => 8080 },
   on_listen_error => sub { die "Cannot listen - $_[-1]\n" },
);

$loop->run;

显然,这个特别小的示例并未演示任何异步,但您可以完全访问所有IO::Async系统,以便稍后推迟和响应。

答案 1 :(得分:0)

所以接下来的评论 - 我对你用来给你一个特定回答的东西知之甚少,但可以提供一些通用的东西。

使用线程将'async'作为Perl脚本的一部分:

#!/usr/bin/perl

use strict;
use warnings;

use threads;
use Thread::Queue; 

my $input_q = Thread::Queue -> new();
my $success_q = Thread::Queue -> new(); 
my $failure_q = Thread::Queue -> new();

my $thread_count = 4; 

sub spinoff_thread {
    while ( my $target = $input_q -> dequeue() )
    {
       #do something to $target
       my @results = `ping -c 10 -i 1 $target`;
       if ( $? ) { 
           $failure_q -> enqueue ( $target );
       }
       else {
           $success_q -> enqueue ( $target );
       }
    } 
}

#main bit

for ( 1..$thread_count ) {
    my $thr = threads -> create ( \&spinoff_thread );
}

foreach my $server ( "server1", "server2", "server3", "server4", "server5" ) {
  $input_q -> enqueue ( $server );
}

$input_q -> end(); #will cause threads to 'bail out' because that while loop will go 'undef'); 

 #wait for threads to complete. 
foreach my $thr ( threads -> list() ) {
   $thr -> join();
}


print "Fail:\n", join ("\n", $failure_q -> dequeue() ), "\n";
print "Success:\n"; join ( "\n", $success_q -> dequeue() ), "\n";

关键点在于你的线程 - 基本上是子程序 - 并且可以使用队列来回传递信息。 end队列是处理告诉线程终止的好方法 - 当然还有其他方法。