3

私はかなり普通の Web サービス (古い学校の asmx) を持っています。メソッドの 1 つは、クライアントに返される結果に関係のない非同期処理を開始します。うまくいけば、以下の小さなスニペットが理にかなっています。

[System.Web.Services.WebMethod]
public List<Foo> SampleWebMethod(string id)
{
    // sample db query
    var foo = db.Query<Foo>("WHERE id=@0",id);

    // kick of async stuff here - for example firing off emails
    // dont wait to send result
    DoAsyncStuffHere();

    return foo;

}

DoAsyncStuffHere メソッドの最初の実装では、ThreadPool.QueueUserWorkItem を利用しました。したがって、次のようになります。

public void DoAsyncStuffHere()
{
    ThreadPool.QueueUserWorkItem(delegate
    {
        // DO WORK HERE
    });
}

このアプローチは、低負荷条件下でうまく機能します。ただし、かなりの高負荷に耐えられるものが必要です。したがって、生産者/消費者のパターンが最善の方法のようです。

私が混乱しているのは、Web サービスのすべてのインスタンスで、キューによって実行されるすべての作業を単一のスレッドに制限する方法です。Web サービスの任意のインスタンスがアクセスできる単一のキューを設定するにはどうすればよいでしょうか?

4

3 に答える 3

5

System.Collections.Concurrent.BlockingCollection<T>System.Collections.Concurrent.ConcurrentQueue<T>基になるコレクションとして使用できます。
名前空間の名前が示すように、コレクションはスレッド セーフです。

メソッドを使用して、コンシューマー スレッド (またはいくつか) を開始し、コレクションからアイテムをプルしますTake()。利用可能なアイテムがない場合、スレッドはブロックされます。

DoAsyncStuffHere メソッドは、項目を BlockingCollection に追加します。これらのアイテムは、開始されていないSystem.Threading.Tasks.Taskオブジェクトである可能性があります。その場合、コンシューマ スレッドStartは、コレクションからタスクを取得した後のタスクになります。

于 2012-05-11T14:27:15.353 に答える
1

これを行う簡単な方法の 1 つは、キューをデータベース テーブルとして実装することです。

プロデューサは、Web サービスの各インスタンスによって処理される要求スレッドです。

コンシューマーは、キューを監視して項目を 1 つずつ処理する、あらゆる種類の継続的に実行されるプロセス (Windows フォーム アプリ、Windows サービス、データベース ジョブなど) である可能性があります。

于 2012-05-11T14:19:36.580 に答える
1

これを行うことはできませんThreadPool-ワーカースレッドを起動する静的コンストラクターを使用できます。DoAsyncStuffHere実行したい作業のキューにその作業項目を挿入することができ、ワーカー スレッドは作業する項目がキューにあるかどうかを確認できます。もしそうなら、それは仕事をします、そうでなければ、数ミリの間スリープします。

静的コンストラクターは、一度だけ呼び出されることを保証し、単一のスレッドのみを起動する必要があります (私が知らない奇妙な .NET エッジ ケースがない限り)。

例のレイアウトを次に示します。おそらく、キューにロックを実装し、ワーカー スレッドにもう少し洗練された機能を追加する必要がありますが、以前にこのパターンを使用して成功したことがあります。オブジェクトは、ワーカー スレッドに渡す情報のWorkItem状態を保持できます。

public static WebService() 
{
  new Thread(WorkerThread).Start();
  WorkQueue = new Queue<WorkItem>();
}

public static void WorkerThread() 
{
  while(true)
  {
    if(WorkQueue.Any()) 
    {
      WorkQueue.Dequeue().DoWork();
    }
    else
    {
      Thread.Sleep(100);
    }
  }
}

public static Queue<WorkItem> WorkQueue { get; set; }

[System.Web.Services.WebMethod]
public List<Foo> SampleWebMethod(string id)
{
  WorkQueue.Queue(newWorkItem());
}
于 2012-05-11T14:21:13.880 に答える