2009-07-02 5 views
5

IO::Selectによって同期的にポーリングされる多数のクライアントおよびサーバーソケット(管理対象コンポーネントに接続して保持するクライアントと同様、サーバーサービスも含む)を開発しようとしています。アイデアはI/Oを処理したり、ワーカースレッドのプールを介して発生する処理要求を要求したりすることでした。PerlでのノンブロッキングI/O操作は1つのスレッドに制限されていますか?良いデザインですか?

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

ハンドルおよび/または参照を共有できないことを知る前に、計画ではselect()のスレッドがポーリングを処理し、関連するハンドルをスレッドプールにまたがってThreadQueueに配置しました。実際には読み書きを行います。 (もちろん、selectで使用されている実際の記述子セットの変更は、スレッドセーフで、1つのスレッドのみで実行されるように設計していました。つまり、select()を実行しているため実行中ではありません。 )

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

この状況から生じる1つの問題は、select()にタイムアウトを与えなければならないことと、それほど大きな記述子をポーリングするのに問題が生じないほど十分に高いと予想し、実際のI/Oセットメンバーシップがポーリングプロセスで検出された場合は、select()が早期に返って問題の軽減につながることを理解しています。私はむしろ別のスレッドから覚醒する方法を持っていますが、ハンドルを共有することはできないので、私はそれをやり遂げる方法も簡単に考えることもできず、そうすることで値を見ることもできません。とにかく目を覚ますのが適切なときに、他のスレッドは何を知りますか?select()

回避策がない場合、Perlでこのタイプのサービスに適したデザインパターンは何ですか?私はスケーラビリティと同時I/Oのかなりの量が必要です。そのため、各リスニングソケットやクライアントプロセス、サーバープロセスのスレッドを生成するのではなく、ノンブロッキングルートを使用します。最近ではソケットを扱うときには扱わないレベルの言語があります。Javaの土地では標準的な習慣のようですが、java.nio.*はシステム指向プログラミングの対象外です。たぶんそれは私の印象です。とにかく、私はそうしたくありません。

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

EDIT:P.S.間違いなく、これらのパフォーマンス要件とこの設計を持つプログラムは、おそらくPerlで書かれていないはずです。しかし、私はPerlで非常に洗練されたサービスが大量に生成されていることを知っています。

答えて

5

いくつかのより大きい設計上の質問を一掃して、perlスレッド間でファイルハンドルを共有する方法をいくつか提案できます。一つは、スレッドルーチン開始または単に新しいスレッドでそれを参照する$clientを渡すことが

$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); 
}; 

または1:

$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設計のために、一つは基礎となるFDをenqueue()ことfdsだけを排他的に使うことができ、Perlのビットベクトル形式はselectです。

+0

興味深い提案。私は、基礎をなすFDを通過させ、後でそれを取り戻すアプローチを特に好む。 ファイルハンドルを初期化し、後でスレッドのIO :: Socketに割り当てる方法を提案できますか?むしろ、あるスレッドでソケットを作成し、別のスレッドでソケットを操作しないでください。 IO :: Handle-> newのような一般的なことをすることは可能ですか? –

+0

アレックス、擬似コードなしで、私はここであなたの質問の詳細を理解するか分からない。しかし、 'IO :: Socket :: INET'と 'IO :: Socket :: INET-> new_from_fd($ my_duplicated_fd、 "r +")'を使用すると、IO :: Socketオブジェクトが得られます。 – pilcrow

+0

ああ、私はIO :: Socket :: INETがIO :: Handleのサブクラスであることを認識しませんでした。意味をなさない –

関連する問題