【问题标题】:Optimising Method Calls on Dynamic Type优化动态类型的方法调用
【发布时间】:2014-03-27 06:57:21
【问题描述】:

我有以下代码实例化一个注册的 COM 对象

private dynamic server = null // Global variable.
...
Type type = Type.GetTypeFromProgID("Svr.GrpCall");
this.server = Activator.CreateInstance(type);

我可以使用非常直观的表示法从这个 COM/dynamic 对象调用方法

string expectedResult = this.server.GroupInit(someString, someBoolean);

对于单个调用,通过动态语言运行时 (DLR) 调用此类方法的性能是可行的。但是,对于一个要求,我需要对数千条记录使用双 for 循环,该循环使用 COM 对象中返回 void 的方法

for (int i = 0; i < MAXREC; i++)
    for (int j = 0; j < MAXFIELDS; j++)
        this.server.MakeRecord(s1, s2, str);

这是 MASSIVELY 慢。我知道这一点,Eric Lippert 的回答 https://stackoverflow.com/a/7480977/626442 给出了这种性能瓶颈的确切原因。

为了解决这个问题,我尝试为处于压力下的 MakeRecord 方法定义一个全局 Action

private Action<short, short, string> makeRecord;

计划在上面的 for 循环中使用它。在使用这个Action 之前,我尝试先初始化服务器(如上),然后使用

makeRecord 委托分配给COM 方法
Type type = Type.GetTypeFromProgID("Svr.GrpCall");
this.server = Activator.CreateInstance(type);

MethodInfo methodInfo = type.GetMethod("MakeRecord");
makeRecord = (Action<short, short, string>)Delegate.CreateDelegate(type, methodInfo);

但是type.GetMethod("MakeRecord") 正在返回null。所以,我的问题是,

  1. 如果这 IS 是正确的方法 来加快我的 dynamic 调用,我如何将 COM 方法 MakeRecord 分配给我的 Action委托?

  2. 如果这不是正确的方法来加快我的dynamic 调用,是什么?

感谢您的宝贵时间。


我也试过做

object o = Activator.CreateInstance(type);
MethodInfo methodInfo = o.GetType().GetMethod("MakeRec");

【问题讨论】:

    标签: c# performance com dynamic-language-runtime


    【解决方案1】:

    你怎么知道缓慢的行为是由于使用了dynamic

    • 您是否尝试过对 COM 接口使用强类型托管包装器并直接调用它们(即不使用 dynamic 并且不使用任何反射方法)?您可以添加对 COM 程序集本身的引用以自动创建托管包装器。
    • 您是否尝试过在调试器外部运行您的代码?在调试器中运行代码会导致对本机代码的方法调用(包括 COM 接口调用)的性能损失高达 100:1。
    • 您是否考虑过更新接口以提供所需算法的更直接实现,从而可以在托管代码中进行更少的函数调用?

    【讨论】:

    • 非常感谢您的回复。我已经分析了代码,可以看到是对 COM 对象的dynamic 调用很慢。众所周知,这些调用可能会非常慢,因为 DLR 必须在每次调用时都神奇地工作(描述为 here)。对于第一点,您的意思是使用“Tlbimp.exe”创建一个 C# 包装器吗?我已经在发布模式下运行了代码,结果是一样的。 COM 库,因为它是第三方和遗留的。也没有办法优化我对调用的使用,因为它是数据情况的剪切重量......
    • 在分析器中,您如何区分dynamic 的开销和方法本身的成本?如果MakeRecord 本身是一个慢速方法,那么你是否使用dynamic 并不重要,因为那不是瓶颈。
    • 是的,我知道这一点。我知道这种方法“不慢”的原因是遗留的 COM 库带有一个旧的示例 VB6 应用程序。此应用程序可以“直接”调用 COM 方法,这可以在 5 秒内调用 MakeRecord 6000 次。当我在 C# 中使用dynamic 执行完全相同的操作时,这一次(对于完全相同的数据集)增加到大约 1 分钟。再次感谢您的宝贵时间...
    • Sam,在回复您的评论之前,我已经离开了一段时间,因为我一直在查看您的个人资料 -> ANTLR -> Terence Parr 的谈话 -> 购买书籍等!我对这项工作感到惊讶。我最近写了一个通用语法高亮器(与 ANTLR 相比没有),最近被要求为保险行业中使用的一些伪代码重写一个旧的 C++ 编译器/静态分析器,还添加了不同的语言格式......跨度>
    • 一开始我“咽了口口水”,以为这会很困难(但很有趣)——然后我找到了 ANTLR!在我发起全面攻击之前,可以通过电子邮件向您发送一些关于 ANTLR 的简短问题吗?
    猜你喜欢
    • 1970-01-01
    • 2014-02-07
    • 1970-01-01
    • 2018-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    相关资源
    最近更新 更多