【问题标题】:TransactionScope performance issuesTransactionScope 性能问题
【发布时间】:2013-07-22 08:09:25
【问题描述】:

在我的服务器端代码 (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;
     }

 }

【问题讨论】:

    标签: c# performance wcf transactionscope


    【解决方案1】:

    删除您的“入队”行,看看问题是否仍然存在。

    另一件事,我很好奇在事务范围内执行的“短操作”。他们可能将事务协调器从 LTM 升级到 MSDTC,这可能解释了并发命中数增加时的缓慢。

    【讨论】:

      【解决方案2】:

      初步回答:

      如果我使用简单的 List 而不是 ConcurrentQueue 来测试它(我没有安装 .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);
      

      基本上开始迭代队列,这会阻塞队列,这会导致仍在启动的线程在尝试将项目添加到队列时冻结,进而导致事务超时。

      你能在没有上面提到的控制台写行的情况下试试吗? 另外,请尝试使用普通列表。

      解决方案是在尝试执行 max/min/avg/total 函数之前等待线程完成。

      需要注意的一点是,我在测试中得到的总数不是完整的 100 或 200。它只是稍微低于一点,这意味着仍有线程在启动。

      更新:

      如果有帮助的话。如果我在方法中移动 enqueue 调用,我遇到的任何问题都会得到解决。这对你的情况有用吗?

      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;
      }
      

      【讨论】:

      • 不能使用列表,因为队列正在被多个线程访问。
      • 指出的问题(错误地)是事务范围,但我认为问题出在并发队列上,因为这会停止线程的执行,进而导致事务范围出现问题。解决问题,而不是解决副作用。
      • 您实际上并没有解决问题,而是创建了一个新问题。当存在争用时,并发队列会暂停线程的一些执行。还有开销,因为它必须检查是否存在争用。删除该检查将导致数据损坏。你正在用一个问题换另一个问题。在这种情况下,并发访问是必须
      • 好的,但不幸的是,当前强制并发访问的方法在使用事务范围时会导致异常。如果 OP 提到了并发访问的要求,那么我们也会知道。原始问题中没有提到它。事实仍然是,如果您在事务正在运行时阻止线程的执行,则可能会导致问题。
      • 我认为访问队列的 100 个线程会使并发要求隐含......
      猜你喜欢
      • 2010-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-13
      相关资源
      最近更新 更多