3

まず第一に、私はPerlに不慣れです。PerlのRESTAPIで複数(たとえば160)のHTTPGETリクエストを作成したい。次々と実行するのは時間がかかるので、リクエストを並行して実行することを考えていました。したがって、スレッドを使用して同時により多くのリクエストを実行し、並列リクエストの数を10に制限しました。これは、プログラムを初めて実行したとき、40回目のリクエストの後に「メモリ不足」を実行したときに問題なく機能しました。

コードは次のとおりです:(@ urlsにはリクエストの160個のURLが含まれています)

while(@urls) {
  my @threads;
  for (my $j = 0; $j < 10 and @urls; $j++) {
    my $url = shift(@urls);
    push @threads, async { $ua->get($url) };
  }

  for my $thread (@threads) {
  my $response = $thread->join;
  print "$response\n"; 
 }
}

だから私の質問は、なぜ私は最初はメモリを使い果たしていないのに、2回目は(私のコードで重要な何かを見逃しているのですか)?そして、それを防ぐために私は何ができますか?または、並列GETリクエストを実行するためのより良い方法はありますか?

4

2 に答える 2

1

最初の実行で OOM エラーが発生しないのに、2 回目の実行で OOM エラーが発生する理由がわかりません。Perl スクリプトを実行して perl バイナリが終了すると、すべてのメモリが解放されて OS に戻されます。実行間で何も保持されません。毎回まったく同じデータが REST サービスから返されますか? たぶん、2 回目に実行したときにさらに多くのデータがあり、限界を超えている可能性があります。

私が気付いた問題の 1 つは、10 個のスレッドを起動し、それらを最後まで実行してから、さらに 10 個のスレッドを生成していることです。より良い解決策は、ワーカー スレッド モデルです。プログラムの開始時に 10 個のスレッド (または任意の数) を生成し、URL をキューに入れ、スレッドがキュー自体を処理できるようにします。役立つ簡単な例を次に示します。

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

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

my @thr = map {
    threads->create(sub {
        my @responses = ();
        while (defined (my $url = $q->dequeue())) {
            push @responses, $ua->get($url);
        }
        return @responses;
    });
} 1..10;

$q->enqueue($_) for @urls;
$q->enqueue(undef) for 1..10;

foreach (@thr) {
    my @responses_of_this_thread = $_->join();
    print for @responses_of_this_thread;
}

注、これが機能することを確認するためにこれをテストしていません。この例では、新しいスレッド キューを作成し、10 個のワーカー スレッドを生成します。各スレッドは、読み取るものがあるまで dequeue メソッドでブロックされます。次に、持っているすべての URL とundeffor each スレッドをキューに入れます。これundefにより、実行する作業がなくなったときにスレッドを終了できます。この時点で、スレッドが通過して作業を処理し、最後に結合を介して応答を収集します。

于 2012-10-24T15:28:43.830 に答える
0

非同期ソリューションPerlが必要なときはいつでも、最初にPOEフレームワークを調べます。この特定のケースでは、POE HTTPリクエストモジュールを使用しました。これにより、複数のリクエストを同時に送信し、httpレスポンスを処理できるコールバックメカニズムを提供できます。

Perlスレッドは恐ろしく、特にそれらを結合または切り離すときに、アプリケーションをクラッシュさせる可能性があります。応答の処理に時間がかからない場合は、シングルスレッドのPOEソリューションが適切に機能します。

ただし、長時間実行されるタスクが原因でアプリケーションがブロックされるため、スレッド化に依存する必要がある場合もあります。そのような場合、アプリケーションで何かを開始する前に、特定の数のスレッドを作成します。次に、Thread :: Queueを使用して、メインスレッドからこれらのワーカーにデータを渡し、それらを結合/切り離すことはありません。安定性のために常にそれらを保持してください。(すべての場合に理想的なソリューションではありません。)

POEは現在スレッドをサポートしており、各スレッドはPOE::Kernelを実行できます。カーネルは、TCPソケット(POEが優れたブロック解除インターフェースを提供します)を介して相互に通信できます。

于 2012-10-24T20:32:32.803 に答える