2

ConcurrentQueue と BlockingCollection について助けが必要です。

シナリオでは、リクエストを調整し、1 秒あたり 1 リクエストの制限に準拠しようとしています。キューからアイテムをデキューすると、調整が発生します。アプリケーションは MVC 4 アプリであるため、いつでも複数のプロデューサーが存在する可能性があり、私が連絡しているコンシューマー/Web サービスは 1 つだけです。

  • プロデューサーGetUser(string url)はリクエストをキューに追加します。リクエストは単なる URL です。
  • 制限に違反していないことを確認するためにいくつかのチェックを実行して、BlockingCollection の最初のアイテムを処理します。
  • コンシューマーからの応答をダウンロードする
  • 次に、何らかの方法でダウンロード応答を呼び出し元のメソッドに返します。抑制されたダウンロード

つまり、キュー内のアイテムを処理し、応答をダウンロードして、呼び出し元のメソッドに送り返したいと思います。呼び出し元のメソッドに送り返すことは、私が立ち往生している場所です。ここにはどのようなオプションがありますか?

//I want to do something like this, and wait for the throttled response to return
public class WebService()
{
    public string GetUser(string name) 
    {
         var url = buildUrl(name);

         var response = string.Empty;

         var downloadTask = Task.Factory.StartNew( () => {
               response = WebServiceHelper.ThrottledDownload(url);
         });
         downloadTask.Wait();
         return response;
    }
}

public static class WebServiceHelper()
{
  private static BlockingCollection<Request> requests = new BlockingCollection<Request>();

  static WebServiceHelper()
  {
       foreach(var item in requests.GetEnumerableConsumer()) {
         string response = DoWork(item.Url);
         //How can i send this back to the calling method?
       }
  }

  public static string ThrottledDownload(string url)
  {
     //Add the request to the blocking queue 
     requests.Add(new Request(url, someId));

     //How do i get the result of the DoWork method?
  } 
}
4

1 に答える 1

1

ThrottledDownおそらく、メソッドに「結果を返す」ことは望ましくありません。少なくとも、私はそうは思わないでしょう。それをしたい場合は、ある種のブロッキング呼び出しを行う必要があります。またはTask、継続して a を使用します...おそらくasyncC#5で。

メインスレッドが何をしているのかはまだ不明です。コンシューマ スレッドが 1 秒間隔で処理する一連のリクエストをキューに入れていると思います (おそらく、クエリしているサーバーによって抑制されるのを防ぐためです)。次に、メインスレッド (または何か) に通知して、何かを実行できるようにする必要があります。

あなたのプログラムの流れはまだ不明です。

メインスレッドに何をさせたいか (そしてどのような情報を処理させたいか) に応じて、いくつかのオプションがあります。あなたはできる:

  • BlockingCollectionの結果を作成します。コンシューマがリクエストを完了すると、そのコレクションにオブジェクトが追加されます。メイン スレッドは、そのコレクションをポーリングして、要求の完了の通知を取得します。
  • 上記のバリエーションは、パイプラインを使用することです。1 つのスレッドが要求をキューに入れます。1 つのスレッドが要求をデキューし、Web 要求を作成してから、結果を別のキューに入れます。3 番目のスレッドがその 2 番目のキューを処理します。
  • 各オブジェクトにイベント (つまりManualResetEventSlim、たとえば) を追加しRequestます。コンシューマはSet、リクエストを完了すると、そのイベントを呼び出します。メイン スレッドは、そのイベントを待機するか、定期的にポーリングします。
  • コンシューマーにコールバック関数を実行させます (コンパイル時に定義するかRequest、キューに追加するオブジェクトに渡します)。そのコールバック関数は、メイン スレッドに通知したり、結果をログに記録したり、何でも好きなことを行うことができます。

繰り返しますが、アプリケーションと解決しようとしている上位レベルの問題に関する詳細情報がなければ、より具体的な推奨事項を作成することはかなり困難です。

于 2013-03-26T20:30:46.600 に答える