首页 > 解决方案 > Thread::Queue 如何在线程之间平均分配作业

问题描述

这是代码:

#!/usr/bin/perl

use strict;
use warnings;
use threads;
use Thread::Queue;

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

sub run_queries {
    my $n = shift;

    print "$n\n-------------\n";
    # $queue->dequeue_nb() does the same
    while (defined(my $text = $queue->dequeue())) {
        print "$text\n";
    }
}

my @threads;
push(@threads, threads->create(\&run_queries, 1));
push(@threads, threads->create(\&run_queries, 2));
push(@threads, threads->create(\&run_queries, 3));
push(@threads, threads->create(\&run_queries, 4));

for (my $i = 0; $i < 12; $i++)
{
    $queue->enqueue($i);
}

$queue->end();
foreach (@threads) {
    $_->join();
}

输出:

1
-------------
2
-------------
3
-------------
4
-------------
0
1
2
3
... all the items here    

我预计输出将在线程之间均匀分布,一旦一个线程从队列中取出项目,第二个线程将激活并开始处理下一个项目。

但实际上我们看到一个线程正在处理所有事情,而其他线程则处于空闲状态。

我需要做什么才能在线程之间平均分配作业?

标签: multithreadingperl

解决方案


是什么让你认为这是一个线程?

改变

print "$text\n";

print "[$n] $text\n";

或者

print "[" . threads->tid . "] $text\n";

样本输出:

1
-------------
2
-------------
3
-------------
4
-------------
[2] 0
[1] 1
[2] 2
[4] 3
[3] 4
[3] 5
[1] 6
[1] 7
[2] 8
[1] 9
[2] 10
[4] 11

您可能还想尝试使用

use Time::HiRes qw( sleep );

print "[" . threads->tid . "] START $text\n";
sleep(rand()+1);  # [1,2) seconds
print "[" . threads->tid . "] END   $text\n";

# After the loop.
print "[" . threads->tid . "] EXIT\n";

样本输出:

[2] START 0 \
[3] START 1  \ All the workers start right off the bat.
[4] START 2  /
[1] START 3 /
[1] END   3 \ As soon as a worker finishes one job, 
[1] START 4 / it starts the next available job.
[4] END   2
[4] START 5
[3] END   1
[3] START 6
[2] END   0
[2] START 7
[1] END   4
[1] START 8
[4] END   5
[4] START 9
[1] END   8
[1] START 10
[2] END   7
[2] START 11
[3] END   6 \ There are no jobs left. Because ->end was called, it exits. 
[3] EXIT    / Otherwise, it would block until ->enqueue or ->end is called.
[4] END   9   
[4] EXIT      
[2] END   11
[2] EXIT
[1] END   10
[1] EXIT

推荐阅读