【问题标题】:How to avoid slowdown due to locked code?如何避免因锁定代码而导致减速?
【发布时间】:2013-04-30 02:29:25
【问题描述】:

我想知道即使代码从未执行过,一段锁定的代码如何会减慢我的代码速度。下面是一个例子:

public void Test_PerformanceUnit()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    Random r = new Random();
    for (int i = 0; i < 10000; i++)
    {
        testRand(r);
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedTicks);
}

public object testRand(Random r)
{
    if (r.Next(1) > 10)
    {
        lock(this) {
            return null;
        }
    }
    return r;
}

这段代码在我的机器上运行大约 1300 毫秒。如果我们移除锁块(但保留它的主体),我们得到 750 毫秒。几乎是两倍,即使代码从未运行过!

当然,这段代码什么也不做。我在一个类中添加一些惰性初始化时注意到了这一点,代码检查对象是否已初始化,如果没有初始化它。问题是初始化被锁定并且即使在第一次调用之后也会减慢一切。

我的问题是:

  1. 为什么会这样?
  2. 如何避免减速

【问题讨论】:

  • 除非你打算大量使用lock - 我真的不会担心。
  • 我得到了类似的结果,但一个刻度是 100 nano-秒。两次运行都应该花费大约 0 毫秒(即,如果您打印 sw.ElapseMilliseconds。)这种“减速”(大约 0.00006 秒)可能是因为 lock 包含一个 try/finally 块,该块可能正在设置该方法时叫做。尝试将testRand 的内容放入循环本身;那时你会看到几乎没有减速。
  • Similar topic here。结果应该几乎相同。
  • 我已将此追踪到try{}finally{} 声明。如果你使用它(即使是空的,没有嵌入代码)也会出现同样的减速。 lock 语句实现 try{}finally{}
  • 另一个问题有一些启发性的答案:stackoverflow.com/questions/6029804/…

标签: c# performance


【解决方案1】:

关于它发生的原因,已经在 cmets 中讨论过:这是由于 lock 生成的 try ... finally 的初始化。


为了避免这种减速,您可以将锁定特性提取到一个新方法中,这样只有在实际调用该方法时才会初始化锁定机制。

我用这个简单的代码试了一下:

public object testRand(Random r)
{
    if (r.Next(1) > 10)
    {
        return LockingFeature();
    }
    return r;
}

private object LockingFeature()
{
    lock (_lock)
    {
        return null;
    }
}

这是我的时间(以刻度为单位):

your code, no lock   : ~500
your code, with lock : ~1200
my code              : ~500

编辑:我的测试代码(运行速度比没有锁的代码慢一点)实际上是在静态方法上,看起来当代码在对象“内部”运行时,时间是相同的。我据此确定了时间。

【讨论】:

  • 感谢您的回答,这正是我想要的。在我的测试中,您的解决方案比lock 内联运行得更快,但比仅使用return null 慢。我将方法 LockingFeature 定义为 virtual 以避免代码内联,我得到了 100% 的性能。
  • @pieroxy - 关于您的第一个测试的另一件事是,带有锁的testRand() 版本也需要更长的时间来进行 JIT。因此,您可以通过在Stopwatch 开始之前调用testRand() 将其排除在外(可以说是一种预热JIT 编译器的方式)。这大大缩小了差距。尽管如此,Zonko 的代码是一种非常巧妙的处理方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-16
  • 1970-01-01
  • 2021-08-02
  • 1970-01-01
  • 2010-09-09
  • 1970-01-01
相关资源
最近更新 更多