更新:我wrote a program测试下面提到的每种技术的内存含义。毫不奇怪,我发现,确实可以肯定,使用.NET事件的常规方法会比其他方法创建更多的垃圾(这意味着,它实际上确实在创建垃圾,这与其他两个似乎都没有创建的策略相反)任何垃圾)。

确实,我应该一直强调,我对.NET事件中TEventArgs参数的内存开销比对速度的开销更感兴趣。最终,我不得不承认,就所有实际目的而言(就内存和速度而言),成本都是可以忽略的。不过,我认为有趣的是,以“常规”方式引发许多事件确实会花费一些钱,而且在极端情况下,它甚至可能导致第1代垃圾回收,这可能会或可能不会很重要,具体取决于情况(根据我的经验,系统需要越“实时”,更重要的是要牢记在何处创建垃圾以及如何在适当的地方将其最小化)。

这似乎是一个愚蠢的问题。我意识到,例如Windows窗体很容易被认为是“高性能”方案,无休止地连续引发数百甚至数千个事件(例如Control.MouseMove事件)。但是,我仍然想知道,如果期望使用高性能,时间紧迫的代码来设计具有.NET事件的类,是否真的合理?

我主要关心的是一种约定,即对所有事件都使用EventHandler<TEventArgs>之类的东西,其中TEventArgs源自EventArgs,并且很可能是每次引发/处理事件时都必须实例化的类。 (显然,如果只是普通的EventsArgs,则不是这种情况,因为可以使用EventArgs.Empty;但是假设TEventArgs类型包含任何有意义且非常量的信息,则可能需要实例化。)似乎这样会导致更大的结果。 GC的压力超出了我创建高性能库的期望。

也就是说,我能想到的唯一替代方法是:

  • 对事件使用非常规的委托类型(即,不使用EventHandler<TEventArgs>),仅采用不需要对象实例化的参数,例如intdouble等(甚至是string,并将引用传递给现有字符串对象)。
  • 完全跳过事件并使用虚拟方法,从而迫使客户端代码根据需要覆盖它们。这似乎与先前的想法基本上具有相同的效果,但是以某种更可控的方式。

  • 我对.NET事件的GC压力的担心是否毫无根据?如果是这样,我在那里想念什么?或者,是否有第三种选择比我刚才列出的两种更好?

    最佳答案

    在执行任何操作之前,您应该考虑进行某种程度的性能分析,以确保这实际上会带来一个实际的问题。 在诸如UI鼠标移动的情况下,事件发生的频率比机器低,因此对GC行为的影响通常可以忽略不计。请记住,.NET GC非常擅长收集很少引用的短期对象-它是在许多地方引用的中长期对象,这可能会造成问题。

    但是,如果(出于某种原因)确实通过一个问题证明了这一点,则有两种可能的方法可以降低成本。

  • 使用非标准的事件委托签名。 您已经将其标识为可能的替代方法-但是,您始终可以使用将事件参数类型限制为结构的通用签名。传递结构作为参数应该减少在堆上分配参数的情况,以创建此数据的副本为代价。
  • 使用TEventArgs flyweight实现,该实现在使用后回收事件参数的实例。 这可能是一个棘手的命题,因为您需要确保事件处理程序从不存储该参数的实例以供在其他地方使用。但是,如果正确实施,此模式可以大大减少需要管理和收集的轻量类型实例的数量。
  • 10-04 22:50
    查看更多