3

サーバー側コード (WCF) で TransactionScope クラスを使用すると、パフォーマンスの問題が発生します。

私のコードはクライアントからリクエストを受け取り、TransactionScope を作成し、短い操作 (通常は最大 100 ミリ秒) を実行します。

私のサーバー側コードをシミュレートする以下の添付コードを参照してください。100人以上の同時ユーザーがいる場合、1秒以上かかるという問題!!! 新しい TransactionScope を作成します (GetTransaction() メソッドを参照)。

同時ユーザー数が 200 に達すると、TransactionAborted がスローされます。

あなたはなにか考えはありますか?

class Program
     {
         private static ConcurrentQueue<double> m_Queue = new ConcurrentQueue<double>();

     static void Main(string[] args)
     {
         Console.WriteLine("Press any key to start ...");
         Console.ReadKey();

         for (int i = 0; i < 100; i++)
         {
             Thread t = new Thread(new ThreadStart(Method));
             t.IsBackground = true;
             t.Start();
         }

         Thread.Sleep(2000);
         Console.WriteLine("Max {0}, Min {1}, Avg {2}, Total {3}", m_Queue.Max(), m_Queue.Min(), m_Queue.Average(), m_Queue.Count);
         Console.ReadKey();
     }


     private static void Method() 
     {
         using (TransactionScope scope = GetTransaction())
         {
             Thread.Sleep(100);
             scope.Complete();
         }
     }

     public static TransactionScope GetTransaction()
     {
         var start = DateTime.Now;

         TransactionOptions options = new TransactionOptions();
         options.IsolationLevel = IsolationLevel.ReadCommitted;
         var t = new TransactionScope(TransactionScopeOption.Required, options);

         // Log creation time
         m_Queue.Enqueue((DateTime.Now.Subtract(start)).TotalMilliseconds);

         return t;
     }

 }
4

2 に答える 2

0

最初の答え:

ConcurrentQueue の代わりに単純な List を使用してテストすると (.net 4.5 がインストールされていません)、コードは正常に動作します。

同時に 200 のスレッドを開始するため、次の行は次のようになります。

Console.WriteLine("Max {0}, Min {1}, Avg {2}, Total {3}", m_Queue.Max(), m_Queue.Min(), m_Queue.Average(), m_Queue.Count);

基本的に、キューの反復処理が開始され、キューがブロックされます。これにより、アイテムをキューに追加しようとすると、開始中のスレッドがフリーズし、トランザクションでタイムアウトが発生します。

上記の console-writeline なしで試すことができますか? また、通常のリストで試してみてください。

解決策は、max/min/avg/total 関数を実行する前に、スレッドが終了するのを待つことです。

注意すべきことの 1 つは、テストで取得した合計が 100 または 200 の完全な数ではないことです。これはほんの少し下にあり、まだスレッドが起動していることを意味します。

アップデート:

それが役立つ場合。メソッドでエンキュー呼び出しを移動すると、私が抱えている問題はすべて解決されます。それはあなたの状況でうまくいきますか?

public static TransactionScope GetTransaction() {
    var start = DateTime.Now;

    // Log creation time
    m_Queue.Enqueue((DateTime.Now.Subtract(start)).TotalMilliseconds);

    TransactionOptions options = new TransactionOptions();
    options.IsolationLevel = IsolationLevel.ReadCommitted;
    var t = new TransactionScope(TransactionScopeOption.Required, options);

    return t;
}
于 2013-07-22T08:32:28.733 に答える