TransactionScope性能问题

本文关键字:问题 性能 TransactionScope | 更新日期: 2023-09-27 18:24:16

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

TransactionScope性能问题

删除"enqueue"行,看看问题是否仍然存在。

还有一件事,我很好奇在事务范围内执行的"短操作"。他们可能正在将事务协调器从LTM升级到MSDTC,这可能解释了并发命中率更高的缓慢性。

初始答案:

如果我用一个简单的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。它只是略低于,这意味着仍有线程在启动。

更新:

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

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