4

私は Perl で実装されたプロジェクトに取り組んでおり、スレッドを使用して作業を分散することを考えました。タスクは互いに独立して実行でき、メモリ内の共有データからのみ読み取ることができるからです。しかし、パフォーマンスは私が期待するほどではありません。そのため、いくつかの調査の結果、Perl のスレッドは基本的に問題があると結論付けることができますが、単一の共有変数を実装するとすぐにパフォーマンスが低下するのではないかと考え続けています。

たとえば、この小さなプログラムは何も共有されておらず、CPU の 75% を消費します (予想どおり)。

use threads;

sub fib {
  my ( $n ) = @_;
  if ( $n < 2 ) {
     return $n;
  } else {
     return fib( $n - 1 ) + fib( $n - 2 );
  }
}

my $thr1 = threads->create( 'fib', 35 );
my $thr2 = threads->create( 'fib', 35 );
my $thr3 = threads->create( 'fib', 35 );

$thr1->join;
$thr2->join;
$thr3->join;

共有変数を導入するとすぐに$a、CPU 使用率は 40% から 50% の間になります。

use threads;
use threads::shared;

my $a : shared;
$a = 1000;

sub fib {
  my ( $n ) = @_;
  if ( $n < 2 ) {
    return $n;
  } else {
    return $a + fib( $n - 1 ) + fib( $n - 2 ); # <-- $a was added here
  }
}

my $thr1 = threads->create( 'fib', 35 );
my $thr2 = threads->create( 'fib', 35 );
my $thr3 = threads->create( 'fib', 35 );

$thr1->join;
$thr2->join;
$thr3->join;

読み取り$a専用であり、ロックは行われませんが、パフォーマンスは低下します。なぜこれが起こるのか興味があります。

現在、Windows XP の Cygwin で Perl 5.10.1 を使用しています。残念ながら、Windows 以外のマシンで (できれば) 最新の Perl を使用してこれをテストすることはできませんでした。

4

2 に答える 2

3

あなたのコードは、同期された構造を巡るタイトなループです。各スレッドに共有変数を (スレッドごとに 1 回だけ) 非共有変数にコピーさせることで、最適化します。

于 2012-05-15T09:14:59.220 に答える
0

Perl では大量のデータを含む共有オブジェクトを作成でき、余分なコピーについて心配する必要はありません。スレッドを使用するかどうかに応じて、共有データは別のスレッドまたはプロセス内に存在するため、ワーカーを生成するときのパフォーマンスへの影響はありません。

use MCE::Hobo;    # use threads okay or parallel module of your choice
use MCE::Shared;

# The module option constructs the object under the shared-manager.
# There's no trace of data inside the main process. The construction
# returns a shared reference containing an id and class name.

my $data = MCE::Shared->share( { module => 'My::Data' } );
my $b;

sub fib {
  my ( $n ) = @_;
  if ( $n < 2 ) {
    return $n;
  } else {
    return $b + fib( $n - 1 ) + fib( $n - 2 );
  }
}

my @thrs;

push @thrs, MCE::Hobo->create( sub { $b = $data->get_keys(1000), fib(35) } );
push @thrs, MCE::Hobo->create( sub { $b = $data->get_keys(2000), fib(35) } );
push @thrs, MCE::Hobo->create( sub { $b = $data->get_keys(3000), fib(35) } );

$_->join() for @thrs;

exit;

# Populate $self with data. When shared, the data resides under the
# shared-manager thread (via threads->create) or process (via fork).

package My::Data;

sub new {
  my $class = shift;
  my %self;

  %self = map { $_ => $_ } 1000 .. 5000;

  bless \%self, $class;
}

# Add any getter methods to suit the application. Supporting multiple
# keys helps reduce the number of trips via IPC. Serialization is
# handled automatically if getter method were to return a hash ref.
# MCE::Shared will use Serial::{Encode,Decode} if available - faster.

sub get_keys {
  my $self = shift;
  if ( wantarray ) {
    return map { $_ => $self->{$_} } @_;
  } else {
    return $self->{$_[0]};
  }
}

1;
于 2018-01-21T07:41:50.920 に答える