5

を介して同期的にポーリングされる多数のクライアントおよびサーバーソケット(サーバーサービス、および管理対象コンポーネントに接続して永続化するクライアント)を含むサービスを開発しようとしていますIO::Select。アイデアは、ワーカースレッドのプールを通じて発生するI/Oおよび/または要求処理のニーズを処理することでした。

Perl()のsharedスレッド間でデータを共有可能にするキーワードにはthreads::shared制限があります。ハンドル参照は、共有できるプリミティブの中にはありません。

ハンドルやハンドル参照を共有できないことを理解する前にselect()、ポーリングを処理するスレッドを作成し、関連するハンドルをThreadQueueスレッドプール全体に分散させて、実際に読み取りと書き込みを行う計画でした。 。(もちろん、によって使用される実際の記述子セットへの変更selectがスレッドセーフであり、1つのスレッドでのみ行われるようにこれを設計していました-実行されるのと同じスレッドであるselect()ため、実行中は明らかになりません。)

ハンドル自体を共有できないため、これは今は発生しないようです。したがって、ポーリングと読み取りおよび書き込みはすべて1つのスレッドから実行する必要があります。これに対する回避策はありますか?スレッド間での実際のシステムコールの分解について言及しています。明らかに、キューとバッファを使用して、データを他のスレッドで生成し、実際に他のスレッドに送信する方法があります。

この状況から発生する問題の1つはselect()、タイムアウトを指定する必要があることです。タイムアウトは、かなり大きな記述子のセットのポーリングで問題が発生しないように十分に高く、タイミングに過度の遅延が発生しないように十分に低くなると予想されます。イベントループ-ただし、ポーリングプロセスで実際のI / Oセットメンバーシップが検出された場合、select()早期に戻るため、問題が部分的に軽減されることは理解しています。別のスレッドからウェイクselect()アップする方法が欲しいのですが、ハンドルを共有できないため、その方法を簡単に考えることも、そうすることの価値を理解することもできません。select()とにかく目を覚ますのが適切なとき、他のスレッドは何を知るつもりですか?

回避策がない場合、Perlでのこのタイプのサービスの適切なデザインパターンは何ですか?かなり高いスケーラビリティと同時I/Oが必要です。そのため、多くの人がより高いレベルを使用しているように、リスニングソケットやクライアントおよび/またはサーバープロセスごとにスレッドを生成するだけでなく、ノンブロッキングルートを使用しました。最近のレベル言語は、ソケットを扱うときに行うことはありません。これは、Javaの世界では一種の標準的な慣習のようでありjava.nio.*、システム指向プログラミングの狭い領域の外では誰も気にしないようです。多分それは私の印象です。とにかく、そんな風にはしたくない。

では、経験豊富なPerlシステムプログラマーの観点から、このようなものをどのように編成する必要がありますか?モノリシックI/Oスレッド+純粋なワーカー(非I / O)スレッド+多数のキュー?ある種の巧妙なハック?私がすでに列挙したものを超えて注意すべきスレッドセーフの落とし穴はありますか?より良い方法はありますか?私はこの種のプログラムをCで設計した豊富な経験がありますが、Perlのイディオムや実行時の特性は持っていません。

編集:PSおそらく、これらのパフォーマンス要件を備えたプログラムとこの設計は、Perlで記述されるべきではないことに気づきました。しかし、Perlで作成された非常に洗練されたサービスが非常にたくさんあるので、それについてはよくわかりません。

4

1 に答える 1

5

いくつかのより大きな設計上の質問をまとめて、perlスレッド間でファイルハンドルを共有するためのいくつかのアプローチを提供できます。

スレッド開始ルーチンに渡す$clientか、単に新しいスレッドでそれを参照することができます。

$client = $server_socket->accept();

threads->new(\&handle_client, $client);
async { handle_client($client) };
# $client will be closed only when all threads' references
# to it pass out of scope.

Thread::Queueデザインの場合、enqueue()基礎となるfdは次のようになります。

$q->enqueue( POSIX::dup(fileno $client) );
# we dup(2) so that $client may safely go out of scope,
# closing its underlying fd but not the duplicate thereof

async {
  my $client = IO::Handle->new_from_fd( $q->dequeue, "r+" );
  handle_client($client);
};

または、fdsだけを使用し、Perlのビットベクトル形式を使用することもできますselect

于 2009-07-02T17:08:36.750 に答える