2010-11-30 7 views
3

基本的には、わずかに異なるニーズを持つ2つのサーバーによる任意の要求を処理できる汎用マルチスレッドTCPサーバーを実装することです。特定のスレッドで同期I/Oを使用するboost asioマルチスレッドtcpサーバー

私の要件は次のとおりです。

  1. 全体の最初の要求が受信されるまで、要求が処理されるように開始することはできません。 (基本的には、要求の全体のサイズを含む固定サイズの要求ヘッダーがあります)。
  2. 要求を処理すると、要求元のクライアントに複数の応答メッセージが返される可能性があります。 IEでは、通常、リクエストは単一のレスポンスで処理できますが、長時間実行されているデータベーストランザクションに応答して、クライアントにpingして、私がまだ動作していることを知らせ、接続をタイムアウトさせないようにする必要があります。

これを達成するために、私は、ブーストv1.44のHTTPサーバーの例#2をかなり厳密に追ってきました。一般的に、この例は単純なケースで機能しています。私が気づいたのは、複数の要求を同時に処理するようにスケールアップすると、私が行った変更によって、すべての要求が1つのスレッドによってシリアルに処理されるという結果になったということです。明らかに、私は何か間違っている。

雇用者の制限のために使用している実際のコード全体を投稿することはできませんが、私は新しい接続を受け入れるために非同期呼び出しを保持していますが、非同期読み取り/書き込みを同期呼び出し。あなたが見る必要があると思う特定の作品がある場合は、私ができることを見ることができます。

私が探しているのは、個々の接続が同期I/Oを持つ単一のスレッドによって処理されるマルチスレッドTCPサーバー用のboost :: asioの使い方の指針です。繰り返しになりますが、私の抽象化はhttpサーバの例#2(CPUあたり1つのio_service)に基づいていますが、代替に柔軟に対応しています

+1

なぜあなたはasync_read/write呼び出しを削除しましたか?おそらく、io_serviceが本当に必要なスレッド数で構成されていることを確認したでしょうか? – Nim

+0

私は、ASIOがドキュメントに欠けていることが常にわかりました。 –

答えて

0

いくつかの診断:io_service_pool_.get_io_service()の値は、コード?

// from server.cpp 
void server::handle_accept(const boost::system::error_code& e) 
{ 
    if (!e) 
    { 
    new_connection_->start(); 
    new_connection_.reset(new connection(
      io_service_pool_.get_io_service(), request_handler_)); 
    acceptor_.async_accept(new_connection_->socket(), 
     boost::bind(&server::handle_accept, this, 
      boost::asio::placeholders::error)); 
    } 
} 
あなたは new_connection_.reset()に渡す前に一時的に保管する必要があります

。つまり、このテストではget_io_service()を2回コールしないでください。

まず、新しいio_serviceを取得していることを確認する必要があります。

+0

私はそれをしました。返された各io_serviceインスタンスのアドレスを吐き出すためにio_service_poolを装備していましたが、予想通りにアドレスが回転するのを見ました。リクエストハンドラの呼び出しでは、サーバは常に同じスレッドを使用していました(std :: cerrにboost :: current_thread :: get_id()を吐き出す)。また、request_handlerの呼び出しは私の時間の大部分を費やしています。 –

+0

また、参考までに、私は8つのスレッドを使用し、いくつかのマシンに分散した48のクライアントスレッドを使って、サーバーの4コアボックスにいます。 –

+0

あなたの読者の 'io_service'はどうですか?あなたは同期呼び出しを使用しているので、 "読み取りハンドラ"自体はありませんが、おそらくあなたは 'handler :: start()'に他のロジックを持っていて、制御を要求ハンドラに渡すでしょう。 – chrisaycock

0

多くの同期I/Oを実行している場合、並行処理はスレッドの数に制限されます。私はあなたのすべてのあなたの非同期I/O(すなわち:すべての通信、タイマ)のための1つのio_serviceを持っていることをお勧めし、次に同期I/Oを処理する方法を決定します。

シンクロナスI/Oの場合、ピーク並列度を決定する必要があります。これは同期型でI/Oであるため、より多くのCPUスレッドを必要とし、必要なI/O並行性の程度に基づいて決定されます。別のio_serviceを使用し、io_service :: dispatch()を使用して、同期ワークロードを実行するスレッドに作業を分散させます。

このようにすると、他の非同期イベントに対するブロックI/Oコール処理の問題を回避できます。

2

Boost.Asio documentationは、アプリケーションごとに単一のio_serviceを使用し、スレッドプールからio_service::runを呼び出すことを提案しています。

非同期readwritedeadline_timerオブジェクトを組み合わせて使用​​すると、クライアントに定期的にpingを送信できない理由もわかりません。このような設計は、同期readswritesを使用する接続あたりのスレッドよりもほぼ確実に拡張されます。

+0

linuxに軽量スレッドが追加されたため、非同期は接続ごとのスレッドよりも必ずしもスケーラブルではありません。 Windowsは長い間、軽量スレッドを持っています。実際、私はスケーラビリティが劣ることを示すベンチマークを見てきました.http://www.mailinator.com/tymaPaulMultithreaded.pdf古いものは新しいものです... – Eloff

関連する問題