使用事件有多少性能开销?

时间:2013-12-17 21:27:23

标签: c# oop

我对编程很新,而且我对OOP的知识有限,我决定使用事件在我的课程之间进行交流。当然,这将导致相当多的事件。

我想知道使用事件是否还有额外的开销?我假设除非对一个事件采取行动(即,一个类中有一个监听器根据被触发的事件执行一个函数),那么应该没有太大的影响。但是我并不熟悉C#中的事件,并且想要确认是否只是为了触发一个事件而产生额外的额外开销?

5 个答案:

答案 0 :(得分:12)

  

我想知道使用事件是否还有额外的开销?我假设除非对一个事件采取行动(即,一个类中有一个监听器根据被触发的事件执行一个函数),那么应该没有太大的影响。乙

总的来说,这是事实。引发事件的标准模式除了检查调用列表以查看是否有订阅者之外什么都不做,如果没有侦听器则返回,在大多数情况下在性能方面将是非常小的,并且可能不会是一个问题。

即使有订阅者,使用事件的开销仍然相当小,因为它们通过委托调用有效地调用订阅者处理程序,这仍然相对较快(虽然比直接方法调用慢)。只要你不是在非常紧密的循环中这样做,它可能是微不足道的。

话虽如此,这与任何性能问题一样,归结为测量。在没有实际测量的情况下,没有办法知道实际使用情况有多重要。为了确定在您的具体情况下这是否是一个合理的设计选择,您需要分析事件的使用情况,以确保它不是一个重要问题。

答案 1 :(得分:9)

  

是否有使用事件的额外开销?

嗯,是的 - 你有一个MulitcastDelegate,代码检查以查看事件处理程序是否实际附加,等等。

  

是否有显着的额外开销,仅用于触发事件?

啊 - 真正的问题。有开销,但它重要?这只能通过测量来回答。

我的猜测是,您遇到的任何开销都不会很大(否则会有关于在性能关键型应用程序中使用事件的警告,我还没有看到)以及其他部分对您的应用程序的性能影响更大。

答案 2 :(得分:2)

我不确定是否有人量化了开销,但对于大多数用途来说它可能非常小。如果您不熟悉编程,那么您最初可能无法编写超高性能代码(如果您是,您可能不会使用C#,对吧?)

要注意的一件事是已发布事件的范围。您最终可能会遇到特定事件的数十个订阅者,但实际上只有一两个人关心事件的给定实例。这个可以导致显着的开销。在这种情况下,可能值得研究System.Observable反应式编程范式。这可以帮助限制过度广播,允许您只调用那些真正关心给定事件的订阅者。

答案 3 :(得分:0)

万一这么多年以后,如果有人偶然发现了这个问题,我就使用BenchMarkDotNet框架来衡量事件调用所花费的时间。我在1个订阅者和100个订阅者之间做了区分。

使用的测试代码:

        private event EventHandler TestEventSingle;
    private event EventHandler TestEventMultiple;

    public OtherTests()
    {
        TestEventSingle += OtherTests_TestEvent;

        for (int i = 0; i < 100; i++)
        {
            TestEventMultiple += OtherTests_TestEventMultiple;
        }
    }

    private void OtherTests_TestEventMultiple(object sender, EventArgs e)
    {
        //Do something with the event...
    }

    private void OtherTests_TestEvent(object sender, EventArgs e)
    {
        //Do something with the event...
    }

    [Benchmark]
    public void InvokeEvent()
    {
        TestEventSingle.Invoke(this, null);
    }
    [Benchmark]
    public void InvokeEventMore()
    {
        TestEventMultiple.Invoke(this, null);
    }
    [Benchmark]
    public void CallMethod()
    {
        OtherTests_TestEvent(this, null);
    }
    [Benchmark]
    public void CallMethodMore()
    {
        for (int i = 0; i < 100; i++)
        {
            OtherTests_TestEventMultiple(this, null);
        }
    }

测试结果:

<table>
<thead><tr><th>   Method</th><th> Mean</th><th>Error</th><th>StdDev</th>
</tr>
</thead><tbody><tr><td>InvokeEvent</td><td>1.6774 ns</td><td>0.0246 ns</td><td>0.0230 ns</td>
</tr><tr><td>InvokeEventMore</td><td>192.2076 ns</td><td>3.6115 ns</td><td>3.3782 ns</td>
</tr><tr><td>CallMethod</td><td>0.0317 ns</td><td>0.0106 ns</td><td>0.0099 ns</td>
</tr><tr><td>CallMethodMore</td><td>37.1203 ns</td><td>0.4147 ns</td><td>0.3676 ns</td>
</tr></tbody></table>

答案 4 :(得分:-2)

是的,有开销。是的可能很重要。这也不难证明。事件是一个多播委托,委托就像一个方法一样阻塞直到完成。

这些是比较两者做同样工作量的实际时间: 使用事件 完成时间271271.687毫秒= 271.271687秒

不使用活动 完成时间123214.514毫秒= 123.214514秒

使用事件最佳“适合”的事件。