更新:我wrote a program测试我在下面提到的每种技术的内存含义。 太令人惊讶的是,我发现,果然,使用 .NET 事件的传统方法比其他方法产生更多的垃圾(意思是,它确实会产生垃圾,而不是其他两种策略两者似乎都不会产生任何垃圾)。
真的,我应该一直强调我对 TEventArgs
的 内存 开销更感兴趣.NET 事件中的参数比 速度 方面的成本。最终我不得不承认,就所有实际目的而言——无论是内存还是速度——成本都可以忽略不计。尽管如此,我还是觉得有趣的是,以“传统”方式提出很多事件确实会花费一些——而且在极端情况下,它甚至会导致gen 1 垃圾收集,根据情况可能会或可能无关紧要(根据我的经验,系统需要的“实时”越多,注意垃圾的创建位置以及如何创建垃圾就越重要)在适当的情况下将其最小化)。
这似乎是一个愚蠢的问题。例如,我意识到 Windows 窗体可以很容易地被认为是“高性能”场景,数百甚至数千个事件一直在非常快速地连续引发(例如,Control.MouseMove
事件)。但我仍然想知道,当预期该类将用于高性能、时间关键的代码时,使用 .NET 事件设计一个类是否真的合理。
我主要关心的是使用 EventHandler<TEventArgs>
之类的约定。对于所有事件,其中 TEventArgs
源自 EventArgs
并且很可能是每次引发/处理事件时都必须实例化的类。 (如果它只是简单的 EventsArgs
,显然,情况并非如此,因为 EventArgs.Empty
可以使用;但假设 any 有意义且非常量的信息包含在 TEventArgs
类型中,实例化可能需要。)看起来这会导致比我预期的高性能库要创建的更大的 GC 压力。
也就是说,我能想到的唯一选择是:
- 对事件使用非常规的委托(delegate)类型(即不是
EventHandler<TEventArgs>
),只采用不需要对象实例化的参数,例如int
,double
等(甚至是string
,并传递对现有字符串对象的引用)。 - 完全跳过事件并使用虚拟方法,强制客户端代码根据需要覆盖它们。这似乎与之前的想法具有基本相同的效果,但方式更加可控。
我对 .NET 事件的 GC 压力的担忧一开始就没有根据吗?如果是这样,我在那里错过了什么?或者,有没有比我刚刚列出的两个更好的第三种选择?
最佳答案
不,Winforms 事件发生在人类时间,而不是 CPU 时间。没有人能以足够快的速度移动鼠标来对现代机器施加任何严重的压力。每个单独遍历的像素都没有消息。
更重要的是,委托(delegate)参数对象始终是 gen #0 对象。他们没有坚持足够长的时间来获得晋升。分配和垃圾收集它们都非常便宜。这不是一个真正的问题,不要追那个鬼。
关于.net - 高性能场景下如何处理 "events"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4541672/