【问题标题】:Native c++ dll running slower when called from VB.net vs. running called from native .exe从 VB.net 调用本机 c++ dll 与从本机 .exe 调用运行时运行速度较慢
【发布时间】:2011-08-28 13:54:21
【问题描述】:

我在本机 C++ (Visual C++ 2010) 中有一些代码来处理一些 GB 的文件。我将其编译为 .exe,大约需要 8 分钟。但是我需要从 Visual Basic .net 接口调用它,所以我把它放在一个 .dll 中并创建了一个 c++/cli 包装类来调用我在本机 dll 中的代码。托管代码和本机 dll 之间的唯一交互是调用启动处理的函数。令我惊讶的是,处理所需的时间几乎是 .exe 方式的两倍。我不是真正的 VB.net 专家,所以也许有一些设置或一些我不知道的东西要看。欢迎任何想法。提前致谢。

【问题讨论】:

  • 您的代码中正在发生什么样的处理?您的 exe 文件是否需要 100% 的处理器时间,还是需要大量的文件 I/O?
  • 您是否将本机 C++ 代码放入 lib 或 DLL 中,并确保它与您的本机 exe / .NET 包装器中使用的 lib 完全相同?这是您应该首先尝试的。
  • 处理大文件的代码几乎总是受到文件系统的限制。读取数千兆字节的文件需要一段时间,硬盘非常慢。重要的是文件之前是否被读取并因此缓存在文件系统缓存中,是否有足够的空闲 RAM 允许文件放入缓存以及文件碎片的严重程度。唯一安全的比较方法是使用 same 文件并从冷启动运行计时测试。
  • 代码读取文件,处理信息,创建几个临时文件,创建一些图像,然后完成。处理器以 50% 的速度运行,而在 .exe 模式下则低于 30%。
  • @Daniel:您确定在创建 .NET 包装器时最终没有将 C++ 代码编译为托管代码吗?或者您没有为 .NET 版本使用未优化的调试版本?

标签: .net c++ vb.net dll c++-cli


【解决方案1】:

几个想法:

  • 也许您使用 Release 配置构建了 .exe,但 .dll 设置为 Debug。您有时会看到发布版本和调试版本之间存在很大差异,优化的代码会产生巨大的差异。

  • 如果您的 VB.net 除了调用 C++ 代码之外还执行其他操作,那么它可能会在您的 .dll 消耗的内容之上增加 CPU 负载。在 VB.net 端进行的任何类型的后台处理都可以解释这种差异。要将苹果与苹果进行比较,您应该有一个命令行 VB.net 应用程序,不带 GUI,并且只有一行调用 dll 函数。

  • 如果上述方法没有帮助,我建议您创建一个本地 C++ 应用程序,该应用程序链接到同一个 DLL,并将其与本地 exe 版本进行比较。如果 C++ 和 DLL 版本的性能与 C++ 独立 exe 相同,那么 VB.net 端肯定存在消耗额外 CPU 的东西。另一方面,如果从本机 C++ 调用 DLL 也很慢,那么您应该寻找 exe 与 dll 的构建过程的差异,或 exe 与 dll 模式的宏/条件编译的差异。

祝你好运。

【讨论】:

    【解决方案2】:

    C++/CLI 包装器真的只是调用 DLL 函数,还是它自己加载 DLL,然后继续使用并由 .NET 管理?本机过程是获得自己的线程,还是在 .NET 的上下文中创建线程?我的直觉是 .NET 正在做一些不必要的事情来管理对象、DLL 或线程的生命周期。

    因此,我的建议是添加一个事件来指示 DLL 正在完成它正在做的任何事情,从本机 DLL 启动一个新线程来运行该过程,并立即返回事件句柄。让您的 .NET 在适当的地方等待该句柄。

    【讨论】:

      【解决方案3】:

      不太明白为什么从 DotNet 端调用的本机 dll 可以使处理时间加倍,除非你能提供更多细节。

      但是,如果本机 exe 版本按预期运行,您可以从 DotNet 将本机 exe 作为后台进程运行,通过命令行传递 api 参数。您甚至可以将 exe 的控制台输出重定向到基于 DotNet 的 GUI。

      【讨论】:

        【解决方案4】:

        这很奇怪。我会查看任务管理器中存在的所有列并比较两个进程(工作集大小、页面错误......)。然后我会查看性能监视器并查看缓存管理器的值。最后但并非最不重要的一点是,您可以尝试只从文件中读取而不是写入来查看时间花在了哪里。

        【讨论】:

          【解决方案5】:

          .NET 框架在从其“托管”代码到本机或“非托管”代码的通信中产生了一些开销。 See here for some background.

          因此,您在性能方面所看到的就是我所期望的一般情况。如果原生 DLL 做更多的工作,我预计通信开销(效率损失)的百分比会更低。

          【讨论】:

          • 我理解这个问题的方式是,从托管代码到本机代码只有一个调用。所以通信开销很难解释从 8 分钟到几乎翻倍的时间。
          • 没错,托管类只调用一次本机代码开始处理。
          • -1,您没有仔细阅读问题描述。它清楚地写着“一个启动进程的调用”。
          • 我坚持我的回答。用户进程在Windows下并不是不间断运行的,每次进程中断和恢复时,线程的栈都要保存和恢复。当您在 .NET + 编组的调用代码下运行本机 DLL 代码时,还有更多需要保存和恢复的内容。这是一个测试这个想法的实验:尝试增加用户进程运行的优先级。更少的中断应该意味着更少的开销。
          • 保存吓人的报价;这同样不正确。 .Net 对非托管代码没有施加任何安全性。那仍然在调用 KERNEL32.DLL
          猜你喜欢
          • 1970-01-01
          • 2013-05-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-23
          • 1970-01-01
          相关资源
          最近更新 更多