Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 带锁的函数调用和虚拟调用哪个更快?_C#_.net_Performance_Locking_Virtual Functions - Fatal编程技术网

C# 带锁的函数调用和虚拟调用哪个更快?

C# 带锁的函数调用和虚拟调用哪个更快?,c#,.net,performance,locking,virtual-functions,C#,.net,Performance,Locking,Virtual Functions,我有一个类,目前不需要是线程安全的,但在未来,我们可能会想要一个线程安全的版本。在我看来,我现在可以通过在相关函数周围放置锁来实现线程安全,或者现在可以将它们设置为虚拟函数,并在以后的子类中的重写中在它们周围放置锁。也就是说,今天我可以这样做: public void DoStuff() { lock (this.SyncRoot) { // Do stuff... } } 或者我可以这样做: public virtual void DoStuff()

我有一个类,目前不需要是线程安全的,但在未来,我们可能会想要一个线程安全的版本。在我看来,我现在可以通过在相关函数周围放置锁来实现线程安全,或者现在可以将它们设置为虚拟函数,并在以后的子类中的重写中在它们周围放置锁。也就是说,今天我可以这样做:

public void DoStuff()
{
    lock (this.SyncRoot)
    {
        // Do stuff...
    }
}
或者我可以这样做:

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

现在,哪种方法可以更快地完成任务?

第二种方法,因为虚拟调用非常便宜,锁也是一种附加调用,比虚拟调用本身更昂贵


另外,第二种方法让您在需要时完全实现锁定。

第二种方法,因为虚拟调用非常便宜,所以锁定也是一种附加调用,比虚拟调用本身更昂贵


另外,第二种方法让您在需要时完全实现锁定。

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

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

如果您打算使DoStuff同步并保证它适用于任何给定的子类,那么最好不要将其设置为虚拟,而是使用受保护的虚拟成员来执行实际工作

public void DoStuff()
{
    lock(this.SyncRoot)
    {
        InternalDoStuff();
    }
}

protected virtual void InternalDoStuff()
{
    // do stuff
}
这还为您提供了不锁定当前代码的选项,这意味着DoStuff只需调用InternalDoStuff,而无需使用其他代码,但仍然能够在以后插入它,而无需接触继承的代码


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

如果您打算使DoStuff同步并保证它适用于任何给定的子类,那么最好不要将其设置为虚拟,而是使用受保护的虚拟成员来执行实际工作

public void DoStuff()
{
    lock(this.SyncRoot)
    {
        InternalDoStuff();
    }
}

protected virtual void InternalDoStuff()
{
    // do stuff
}
这还为您提供了不锁定当前代码的选项,这意味着DoStuff只需调用InternalDoStuff,而无需使用其他代码,但仍然能够在以后插入它,而无需接触继承的代码


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

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

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

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


另一方面,一把锁在引擎盖下至少需要一两次原子操作。这样的操作几乎肯定会在CPU管道上造成破坏,因为它们需要内存屏障。

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


另一方面,一把锁在引擎盖下至少需要一两次原子操作。这样的操作几乎肯定会在CPU管道上造成破坏,因为它们需要内存障碍。

Egads,我找不到参考资料,也许它在Joe Duffy的书中,但在另一个线程开始攻击锁之前,锁可能是不起作用的,即延迟创建

此外,该锁无论如何都不会进入内核模式,它基于互锁API


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

Egads,我找不到参考资料,也许它在Joe Duffy的书中,但锁定可能是无效的,直到另一个线程开始攻击它,即惰性创建

此外,此锁不能进入ke 无论如何,rnel模式是基于联锁API的


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

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

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

SyncRoot属性是我只为线程安全版本添加的东西-我应该在问题中更清楚地说明这一点。SyncRoot属性是我只想为线程安全版本添加一些东西——我应该在问题中说得更清楚一些。假设普通情况是无争议的,那么不,至少在Linux和Windows上的锁并不意味着进入内核。然而,现在获取和释放锁需要处理器执行内存屏障指令,这通常是非常昂贵的数百个周期,取决于硬件…内存屏障会降低多CPU和多核效率。假设常见情况是无争用的,那么没有,至少在Linux和Windows上的锁并不意味着进入内核。然而,现在获取和释放锁需要处理器执行内存屏障指令,这通常是非常昂贵的数百个周期,取决于硬件…内存屏障会降低多CPU和多核效率。这里的两个示例都是虚拟的。这就是目的吗?这里的两个例子都是虚拟的。这就是目的吗?