2

コードの一部があります:

class WCFConsoleHostApp : IBank
{
    private static int _instanceCounter;

    public WCFConsoleHostApp ()
        {
        Interlocked.Increment(ref _instanceCounter);
        Console.WriteLine(string.Format("{0:T} Instance nr " + _instanceCounter + " created", DateTime.Now));
        }
    private static int amount;

    static void Main(string[] args)
    {            
        ServiceHost host = new ServiceHost(typeof(WCFConsoleHostApp));
        host.Open();
        Console.WriteLine("Host is running...");
        Console.ReadLine();
    }

    #region IBank Members

    BankOperationResult IBank.Put(int amount)
    {
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Putting...");
        WCFConsoleHostApp.amount += amount;
        Thread.Sleep(20000);
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Putting done");
        return new BankOperationResult { CurrentAmount = WCFConsoleHostApp.amount, Success = true };            
    }

    BankOperationResult IBank.Withdraw(int amount)
    {
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Withdrawing...");
        WCFConsoleHostApp.amount -= amount;
        Thread.Sleep(20000);
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Withdrawing done");
        return new BankOperationResult { CurrentAmount = WCFConsoleHostApp.amount, Success = true };
    }

    #endregion
}

私のテスト クライアント アプリケーションは、50 スレッドでそのサービスを呼び出します (サービスは PerCall です)。私が非常に気がかりなのは、Thread.Sleep(20000) を追加したときです。WCF は、プールとは異なるスレッドを使用して、毎秒 1 つのサービス インスタンスを作成します。

Thread.Sleep(20000) を削除すると、50 個のインスタンスがすぐにインスタンス化され、それを行うために約 2 ~ 4 個のスレッドが使用されます。実際、これは正常だと考えています。

Thread.Sleep がインスタンスの作成でおかしな遅延を引き起こす理由を誰か説明できますか?

4

4 に答える 4

10

実際のサービス実装(IBankインターフェイスの実装)とサービスホストを1つの同じクラスに混在させています。

これは間違いなく良い習慣ではありません。

既定では、WCFは設計上、着信する要求ごとにサービス実装クラスの新しい個別のコピーをインスタンス化します。これにより、サービスの作成がはるかに簡単になります(マルチスレッドに煩わされる必要はありません。各要求は独自のクラスを取得します)。

ただし、これをServiceHostと混合しないでください。数百または数千の要求を処理できるサービスクラスをホストするために必要なサービスホストインスタンスは1つだけです。

つまり、1つのクラスを作成します

class BankImplementation : IBank
{
    private static int _instanceCounter;

    BankOperationResult IBank.Put(int amount)
    {
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Putting...");
        //WCFConsoleHostApp.amount += amount;
        Thread.Sleep(20000);
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Putting done");
        return new BankOperationResult { CurrentAmount = WCFConsoleHostApp.amount, Success = true };            
    }

    BankOperationResult IBank.Withdraw(int amount)
    {
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Withdrawing...");
        //WCFConsoleHostApp.amount -= amount;
        Thread.Sleep(20000);
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Withdrawing done");
        return new BankOperationResult { CurrentAmount = WCFConsoleHostApp.amount, Success = true };
    }
}

サービスコード用に、次にサービスコードをホストするための別の(場合によっては別のプロジェクトでも)次のようにします。

class WCFConsoleHostApp
{

    public WCFConsoleHostApp ()
    {
        Interlocked.Increment(ref _instanceCounter);
        Console.WriteLine(string.Format("{0:T} Instance nr " + _instanceCounter + " created", DateTime.Now));
    }

    static void Main(string[] args)
    {            
        ServiceHost host = new ServiceHost(typeof(BankImplementation));
        host.Open();
        Console.WriteLine("Host is running...");
        Console.ReadLine();

        host.Close();
    }
}

これで、のインスタンスが1つ取得されます。これによりWCFConsoleHostApp、でWCFランタイムが起動し、必要な数のクラスインスタンスをhost.Open()インスタンス化してリクエストを処理します。BankImplementation

更新: WCFサービスも「スロットル」されます。たとえば、同時呼び出しとインスタンスの数を微調整できます。デフォルトでは、10の同時セッションと16の同時呼び出しがあります。サービスがすでに16の同時呼び出しを処理していて、それらがしばらくスリープしている場合、追加のサービスインスタンスは作成および処理されません。

サービススロットリングの詳細については、KennyWolfによるこの優れたブログ投稿を参照してください。必要に応じて、これらの最大値を微調整できます。

于 2009-12-03T06:10:32.620 に答える
2

これが正しいかどうかはわかりませんが...

WCF の動作ではなく、ThreadPool の動作に遭遇している可能性があります。スレッドは開いたままなので、ThreadPool の動作は、通常はリソースを節約するためにスレッド数を抑えようとするため、時間の経過とともにキューに入れられた作業を処理するために追加のスレッドをスピンアップする可能性があります。

したがって、理論的には、WCF は要求ごとに作業項目をキューに入れますが、スレッドは 20 秒間解放されないため、処理されません (つまり、最初の要求を過ぎます)。ThreadPool は 1 秒後にこれを確認し、新しいスレッドを作成し、既存のキューからいくつかの作業を盗みます。毎秒繰り返します。

于 2009-12-03T06:28:15.823 に答える
0

これについて 100% 確信があるわけではありませんが、WCF サービスでスロットリングの問題が発生している可能性があります。この MSDN 記事スロットリングセクションをご覧ください。これが役立つことを願っています。

于 2009-12-03T03:11:31.767 に答える
0

サービスを一時停止している、または実行時間の長いジョブをシミュレートしています。wcf は、サービスを必要とする他のクライアントを処理するために、より多くのスレッドを作成するだけです。

于 2009-12-02T22:55:10.150 に答える