【问题标题】:Which is faster, a function call with a lock, or a virtual call?哪个更快,带锁的函数调用或虚拟调用?
【发布时间】:2011-01-07 19:31:37
【问题描述】:

我有一个当前不需要线程安全的类,但将来我们可能想要制作一个线程安全的版本。在我看来,我现在可以通过在相关函数周围加锁来使其成为线程安全的,或者我现在可以使它们成为虚拟的,然后在后代类的覆盖中加锁。也就是说,今天我可以这样做:

public void DoStuff()
{
    lock (this.SyncRoot)
    {
        // Do stuff...
    }
}

或者我可以这样做:

public virtual void DoStuff()
{
    // Do stuff...
}

今天哪个选项可以更快地完成工作?

【问题讨论】:

  • 这里的两个例子都是虚拟的。这是故意的吗?

标签: c# .net performance locking virtual-functions


【解决方案1】:

第二个,因为虚拟调用非常便宜(锁也是一个额外的调用,它会比虚拟调用本身更昂贵)。

另外,第二个留给你在你需要的时候实现锁定。

【讨论】:

    【解决方案2】:

    虚拟通话几乎肯定会更快。虚拟调用涉及额外的间接级别。锁通常涉及到内核模式的切换——保守估计至少要慢 100 倍。

    【讨论】:

    • 假设常见情况是无竞争的,那么不,至少在Linux和Windows上的锁并不意味着进入内核。然而,现在获取和释放锁需要处理器执行内存屏障指令,这通常是相当昂贵的(数百个周期,取决于硬件)
    • ...内存屏障会扼杀您的多 CPU 和多核效率。
    【解决方案3】:

    如果您打算使DoStuff 同步(并保证它适用于任何给定的子类),那么您最好不要将其设为virtual 并使用@987654323 @member 做实际的工作。

    public void DoStuff()
    {
        lock(this.SyncRoot)
        {
            InternalDoStuff();
        }
    }
    
    protected virtual void InternalDoStuff()
    {
        // do stuff
    }
    

    这也为您提供了 not 在当前代码中locking 的选项(意味着DoStuff 只是调用InternalDoStuff 而没有其他代码),但仍然可以将其滑过以后无需修改继承的代码。

    至于速度,lock 语句的放置不会有任何影响。

    【讨论】:

      【解决方案4】:

      第二个。如果您今天不需要线程安全,请不要这样做。公开SyncRoot 属性,以便将来该方法可以变成线程安全的。但请务必在文档中明确说明该方法不是线程安全的。

      【讨论】:

      • SyncRoot 属性是我只为线程安全版本添加的 - 我应该在问题中更清楚地说明这一点。
      【解决方案5】:

      虚函数调用基本上是数组查找加上间接函数调用。如果虚拟调用是在循环中发生的,即如果虚拟函数调用在同一个实例的同一位置被多次调用,那么在大多数迭代中,它不会比非内联的普通函数调用慢。现代 CPU 分支预测器预测虚拟函数调用的目标,并推测性地执行该目标,同时获取函数的地址。

      另一方面,锁总是在幕后至少涉及一两个原子操作。此类操作几乎肯定会对 CPU 管道造成严重破坏,因为它们需要内存屏障。

      【讨论】:

        【解决方案6】:

        Egads,我找不到参考资料,也许它在 Joe Duffy 的书中,但 Lock 可能在另一个线程开始命中它之前是无操作的(即惰性创建)。

        另外,这个锁无论如何都不会进入内核模式,它是基于 Interlocked### API。

        最后,思考这些主题很有趣,但最好的办法是始终为自己的代码计时。

        【讨论】:

          【解决方案7】:

          我测试了 VB SyncLock,它几乎慢了 300 倍。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-07-02
            • 2010-09-17
            • 2020-05-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-01
            相关资源
            最近更新 更多