3

この問題を考えてみましょう: データベースから 100 件のレコードをフェッチ (たとえば) する必要があるプログラムがあり、それぞれのレコードについて Web サービスから更新された情報を取得する必要があります。このシナリオで並列処理を導入するには、次の 2 つの方法があります。

  1. 新しいスレッドで Web サービスへの各要求を開始します。同時スレッドの数は、何らかの外部パラメーターによって制御されます (または何らかの方法で動的に調整されます)。

  2. 小さなバッチ (それぞれ 10 レコードとしましょう) を作成し、各バッチを個別のスレッド (この例では 10 スレッド) で起動します。

どちらがより良いアプローチで、なぜそう思うのですか?

4

4 に答える 4

6

オプション 3 が最適です。

非同期 IO を使用します。

リクエスト処理が複雑で負荷が高い場合を除き、プログラムは時間の 99% を HTTP リクエストの待機に費やすことになります。

これはまさに Async IO が設計された目的です。Windows ネットワーク スタック (または .net フレームワークなど) にすべての待機を心配させ、単一のスレッドを使用してディスパッチし、結果を「取得」します。

残念ながら、.NET フレームワークでは、これが厄介な問題になっています。raw ソケットまたは Win32 API を使用している場合は簡単です。とにかく C#3 を使用した (テスト済みの) 例を次に示します。

using System.Net; // need this somewhere

// need to declare an class so we can cast our state object back out
class RequestState {
    public WebRequest Request { get; set; }
}

static void Main( string[] args ) {
    // stupid cast neccessary to create the request
    HttpWebRequest request = WebRequest.Create( "http://www.stackoverflow.com" ) as HttpWebRequest;

    request.BeginGetResponse(
        /* callback to be invoked when finished */
        (asyncResult) => { 
            // fetch the request object out of the AsyncState
            var state = (RequestState)asyncResult.AsyncState; 
            var webResponse = state.Request.EndGetResponse( asyncResult ) as HttpWebResponse;

            // there we go;
            Debug.Assert( webResponse.StatusCode == HttpStatusCode.OK ); 

            Console.WriteLine( "Got Response from server:" + webResponse.Server );
        },
        /* pass the request through to our callback */
        new RequestState { Request = request }  
    );

    // blah
    Console.WriteLine( "Waiting for response. Press a key to quit" );
    Console.ReadKey();
}

編集:

.NET の場合、'完了コールバック' は実際にはメイン スレッドではなく ThreadPool スレッドで起動されるため、共有リソースをロックする必要がありますが、スレッドを管理する手間を省くことができます。

于 2008-08-13T23:35:50.270 に答える
2

考慮すべき2つのこと。

1. レコードの処理にはどのくらいの時間がかかりますか?

レコード処理が非常に高速な場合、レコードをスレッドに渡すオーバーヘッドがボトルネックになる可能性があります。この場合、頻繁に引き渡す必要がないように、レコードをバンドルする必要があります。

レコード処理が適度に長時間実行される場合、違いは無視できるため、より単純なアプローチ (スレッドごとに 1 レコード) がおそらく最適です。

2. いくつのスレッドを開始する予定ですか?

スレッドプールを使用していない場合は、スレッドの数を手動で制限するか、データを大きなチャンクに分割する必要があると思います。すべてのレコードに対して新しいスレッドを開始すると、レコード数が多くなるとシステムがスラッシング状態になります。

于 2008-08-13T19:19:32.017 に答える
0

プログラムを実行しているコンピューターがボトルネックではない可能性があります。 HTTP プロトコルには keep-alive ヘッダーがあり、同じソケットで複数の GET 要求を送信できるため、TCP/IP のハンドシェイクを回避できます。残念ながら、.net ライブラリでそれを使用する方法がわかりません。(できるはずです。)

また、リクエストへの回答も遅れる可能性があります。サーバーへの未処理のリクエストが常に一定数あることを確認してみてください。

于 2008-08-13T19:34:24.593 に答える
0

Parallel Fxを取得します。BlockingCollection を見てください。スレッドを使用してレコードのバッチをフィードし、1 ~ n 個のスレッドがコレクションからレコードを取り出してサービスを提供します。コレクションがフィードされる速度と、Web サービスを呼び出すスレッドの数を制御できます。ConfigSection を介して構成可能にし、コレクション Action デリゲートをフィードすることでジェネリックにすると、心ゆくまで再利用できる素敵な小さなバッチャーができあがります。

于 2008-08-13T19:40:41.133 に答える