【问题标题】:How much performance overhead is there in using events?使用事件有多少性能开销?
【发布时间】:2013-12-17 21:27:22
【问题描述】:

我对编程还很陌生,由于我对 OOP 的了解有限,我决定使用事件在我的类之间进行通信。当然,这会导致很多事件。

我想知道使用事件是否有任何额外开销?我假设除非对事件采取行动(即,类中有一个侦听器根据被触发的事件执行函数),否则应该不会产生太大影响。但我对 C# 中的事件并不十分熟悉,只是想确认是否存在仅仅为了触发事件而产生的大量额外开销?

【问题讨论】:

标签: c# oop


【解决方案1】:

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

一般来说,这是真的。引发事件的标准模式只会检查调用列表以查看是否有订阅者,如果没有侦听器则返回,在大多数情况下,这在性能方面非常小,而且很可能不会一个问题。

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

话虽如此,这就像任何性能问题一样,归结为测量。如果不实际测量您的情况,就无法知道实际使用量在实践中的重要性。为了确定在您的特定情况下这是否是一个合理的设计选择,您需要分析事件的使用情况以确保它不是一个重大问题。

【讨论】:

    【解决方案2】:

    如果多年后有人偶然发现这个问题,我使用 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);
        }
    }
    

    测试结果:

    Method Mean Error StdDev
    InvokeEvent 1.6774 ns 0.0246 ns 0.0230 ns
    InvokeEventMore 192.2076 ns 3.6115 ns 3.3782 ns
    CallMethod 0.0317 ns 0.0106 ns 0.0099 ns
    CallMethodMore 37.1203 ns 0.4147 ns 0.3676 ns

    【讨论】:

      【解决方案3】:

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

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

      是否有显着的额外开销仅仅是为了触发一个事件?

      啊——真正的问题。有开销,但它显着吗?这只能通过测量来回答。

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

      【讨论】:

        【解决方案4】:

        我不确定是否有人量化了开销,但对于大多数用途而言,它可能非常小。如果您是编程新手,那么您一开始可能并不打算编写超高性能代码(如果是,您可能不会使用 C#,对吧?)

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

        【讨论】:

        • 这是我以前没有想到的,谢谢你提到这个。
        【解决方案5】:

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

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

        不使用事件 完成时间 123214.514 毫秒 = 123.214514 秒

        使用最“合适”的事件。

        【讨论】:

        • 由于您没有提供您正在测试的代码,我们无法判断这些时间是否有任何有意义的价值。
        猜你喜欢
        • 2010-09-05
        • 2017-09-27
        • 2014-10-18
        • 2012-12-12
        • 1970-01-01
        • 2015-07-12
        • 2010-11-12
        • 1970-01-01
        相关资源
        最近更新 更多