跨应用程序域通信的最小性能惩罚是多少?

19
我试图最小化在同一台机器上跨越AppDomains通信的性能惩罚。在我的示例中,Class A被加载到AppDomain 1中。它创建了一个AppDomain 2,并在那里加载了一个继承自MarshalByRef的Class 2实例,获取了代理并返回。然后Class 1反复调用代理上的一个无返回值方法。
我得到以下结果:
  1. 没有AppDomains,两个类都加载在同一个AppDomain中,第一个重复地调用第二个的方法(该方法没有参数):2400万次方法调用/秒
  2. 两个如上所述的AppDomain,方法没有参数或"bleeding"字符串参数:34万次方法调用/秒
  3. 两个如上所述的AppDomain,一个可序列化的参数(包含两个字符串的数组):6.4万次方法调用/秒
尽管我理解2和3之间(序列化)的性能惩罚,但我真的不理解为什么从情况1到情况2会慢100倍。据我所知,一旦代理被创建,在随后的所有方法调用中必须非常快,因为没有数据从一个AppDomain传输到另一个AppDomain。是否有人知道为什么跨AppDomains通信如此缓慢?我做错了什么吗?
PS1. 我唯一的提示是这里:“跨越AppDomain边界的成本令人尴尬。”我猜他是指序列化...
PS2. 我不计算AppDomain或代理创建时间(我的基准从第一个方法调用开始)
PS3. 我在WinXP SP3机器上使用.NET 3.5。我也尝试过.NET 4.0 Beta 1,没有显着差异。
3个回答

12
如果你数一下每个场景中涉及的IL代码行数,你会发现当使用远程调用时,CLR所做的工作要比直接调用多100倍以上。直接调用只需要几个操作码,但是在远程调用中,涉及到多个类、真实/透明代理、安全检查、序列化等复杂的过程。你需要通过设计来解决这个问题 - 无法通过实现来进行性能提升。

1
+1 我完全同意你的观点。直接调用方法非常简单。通过远程调用进行方法调用则更加繁重,开销也更大。唯一真正的解决方案是良好的应用程序设计,不依赖于跨应用程序域通信的速度。 - jpbochi

1

有没有办法调用一个单一的帮助方法,该方法接受关于您需要调用的方法的次数的参数?跨AppDomain调用性能因实现而异。我相信在CLR 4.0中它可能会显着改善,但我对其中的细节并不完全熟悉。

通常,您希望通过“批处理”调用来避免开销,这可以通过帮助方法实现。


我不明白这将如何对我有所帮助。我的A类中的方法正是这样:不断调用对象的MyMethod()。如果代理调用的成本确实比同一AppDomain对象上的调用大100倍,那么对我的设计影响将会非常巨大。 - Yiannis
3
调用object.MyHelperMethod,它会在另一个AppDomain中重复调用object.MyMethod。如果你需要高性能,并假设/要求跨AppDomain进行高速调用,则这可能会对你的设计产生重大影响。 - Sam Harwell
哦,我明白了! :-) 好的,这当然会让事情变得更快。但是这个例子只是一个玩具,我的真正程序不会每秒调用同一个函数2000万次..! 我将不得不进行各种跨应用程序域调用,这些调用通常必须很快。无论如何,还是谢谢! - Yiannis

0

我看到了相同的结果。我无法解释为什么它要慢那么多,除非是因为它比运行两个不同进程并彼此通信更快。在我的设计中,我面临着类似的困境。最后,我修改了我的设计,创建了独立的应用程序域;在执行期间,该应用程序域能够完成其工作而无需与另一个应用程序域通信...只有在完成时才会报告数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接