【问题标题】:perl Coro shared arrayperl Coro 共享数组
【发布时间】:2015-04-07 05:36:55
【问题描述】:

我有点编程新手,现在对一个简单的任务有点困惑(非常好) - 在 coro 协程之间共享一个数组。

这样的事情(不工作,只需要 40 秒)......

my @array = (1..1000);
$|=0;

sub start_thread($) {
    my $url = shift;
    return async {
        print "starting  $array[0]\n";
        shift @array;
        sleep(2);
      };
}

sub main{
  start_thread $_ for (1..20);
  EV::loop;
}

main;

我已经阅读了 IPC::Sharelite 和 IPC::Share 并尝试了一些东西,但没有任何效果...... 如果有人可以清楚地指出我吗?

【问题讨论】:

  • 这是完整的程序吗?
  • 您的程序给了我以下错误:Can't locate object method "async" via package "2" (perhaps you forgot to load "2"?) at t.py line 6.。请发布整个源文件 (sscce.org)。
  • @pts,他只是省略了use strict; use warnings; use Coro;

标签: perl coroutine


【解决方案1】:

Coro 是一个协作式多任务系统。这意味着一次只能运行一个任务,您可以使用事件系统(例如$cv->recv)让其他任务运行,而不是阻塞调用(例如sleep)。

use AE   qw( );
use Coro qw( async );

sub ae_sleep {
   my ($secs) = @_;
   my $cv = AE::cv();
   my $guard = AE::timer($secs, 0, $cv);
   $cv->recv();
}

sub worker {
   my ($job) = @_;
   my $id = sprintf("Thread %d: Job %s", $Coro::current, $job);
   print("$id: Running...\n");
   ae_sleep(2);
   print("$id: done.\n");
}

{
   my @array = 1..60;

   my @threads;
   for (1..20) {
      push @threads, async {
         while (defined(my $job = shift(@array))) {
            worker($job);
         }
      };
   }

   $_->join() for @threads;
}

如果您使用 Coro::Channel 而不是数组,则可以在启动工作程序后将元素添加到队列中。

use AE            qw( );
use Coro          qw( async );
use Coro::Channel qw( );

sub ae_sleep { ... }  # Same as above

sub worker { ... }  # Same as above

{
   my $q = Coro::Channel->new();

   my @threads;
   for (1..20) {
      push @threads, async {
         while (defined(my $job = $q->get())) {
            worker($job);
         }
      };
   }

   $q->put($_) for 1..60;

   $q->shutdown();
   $_->join() for @threads;
}

如果你想使用真正的线程,很简单:

use threads;
use Thread::Queue qw( );  # 3.01+

sub worker {
   my ($job) = @_;
   my $id = sprintf("Thread %d: Job %s", threads->tid, $job);
   print("$id: Running...\n");
   sleep(2);
   print("$id: done.\n");
}

{
   my $q = Thread::Queue->new();

   my @threads;
   for (1..20) {
      push @threads, async {
         while (defined(my $job = $q->dequeue())) {
            worker($job);
         }
      };
   }

   $q->enqueue($_) for 1..60;

   $q->end();
   $_->join() for @threads;
}

【讨论】:

  • 我正在尝试睡眠,因为我认为它是并发测试的正确方法,但我看起来有多么错误。使用 ae_sleep 就可以了。对于您示例中的其余部分,我需要一些睡眠才能进入我的大脑......
  • sleep 对 Coro 或底层事件循环一无所知。它使进程必须休眠的唯一真正线程。 $cv->recv() 了解 Coro。它知道代码正在等待运行,因此它将让 Coro 将上下文切换到该 Coro 线程。
  • 是的,我明白了(我认为)。
  • 好吧,我不确定,但看起来使用 Coro 并行下载 Web 内容没有任何好处,因为 Parallel::ForkManager 更适合这项任务。
  • P::FM 会做得很好。但 Coro 也会如此,因为大部分时间都花在等待数据到达上。如果你想在 Coro 中使用 LWP,请使用 LWP::Protocol::AnyEvent::http。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-13
  • 2015-08-31
  • 1970-01-01
  • 2013-03-06
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
相关资源
最近更新 更多