【问题标题】:Performance of C++ calls to Java code vs C# codeC++ 调用 Java 代码与 C# 代码的性能
【发布时间】:2010-07-13 14:44:20
【问题描述】:

我正在我的客户端探索一个解决方案,我们必须从我们的 C++ 应用程序调用一个在 C# 和 Java 中都可用的 API。我们希望这是一个跨平台应用程序(PC 和 Mac),因此首选 Java,但性能更重要。我一直在尝试对 C++ 调用 C# 与 Java 的性能进行一些研究,但没有找到任何可靠的信息。思路是使用 JNI 调用 Java API 或托管 C++ 调用 C# API。

有没有人知道什么是更好的性能明智的信息或见解?这些调用可能会被大量执行,因此音量确实会发挥作用。

谢谢!

【问题讨论】:

  • afaik 你不能使用 JNI 从 C/C++ 调用 Java。反过来说:JNI 使您能够调用用 C/C++ 编写的库。
  • JNI 还允许您实例化 JVM 并从 C 调用它
  • 您可以从 C++ 调用 Java,但是如果性能很重要,请减少调用。大多数任务都可以重组,从而减少调用次数。如果您的代码编写得很好,那么这些调用的成本应该不会很大。对于 JNI,成本可能约为 30 个时钟周期,但这实际上取决于您在做什么。
  • 只要避开 System.Windows.Forms.* 子空间,您也可以在 Mac 上使用 C#。微软从一开始就提供了它并自己使用它。既然你关心性能,你不能做 GUI 类型的代码,为什么不使用你觉得舒服的任何一个。

标签: c# java c++ java-native-interface managed-c++


【解决方案1】:

我无法为您提供明确的答案,但我已经完成了对 C 库调用的 JNI(不是相反的)、对包装的 Java 库调用以及 .NET 对 .NET 库调用的 .NET。我没有关于它们的官方编号,但是 .NET 到 .NET 的调用,无论是托管 C++ 还是 C# 都是最简单和最快的。因为它们都是 .NET,所以双方都支持一组通用的数据类型。在其他情况下,在不同语言的数据类型之间进行转换需要大量难看的编组代码。 .NET Framework 的设计意图是不同 .NET 库之间的调用对其原始语言是透明的,并且它做得很好。

另一个考虑因素是,在大容量环境中,各个库的性能可能比互操作性能更受关注。换句话说,如果 Java 库比 C# 库快 25%,那么使用 Java 库可能是有意义的,即使与 C# 的互操作比使用 Java 更快、更容易。

【讨论】:

    【解决方案2】:

    我假设 C# 和 Java API 是相同的。我曾经在 C# 和 Java 都必须通过 interop / JNI 与同一个 C++ 库通信的环境中工作。在性能方面,Java 版本似乎更加一致,因为 API 非常健谈并生成了很多瞬态对象。

    这就是我们调用的样子:

    double myDouble= theCPPWrapper.GetField("foo").AsDouble(); 
    

    theCPPWrapper.GetField(string) 返回一个 JNI Field 类,Field.AsDouble() 方法通过另一层互操作无用...

    所以 GC 充满了瞬态 Field 对象,不知何故 Java 似乎能更好地应对。

    最后的修复是改变 JNI / Interop api 看起来像这样:

    double myDouble = theCPPWrapper.GetFieldAsDouble("foo"); // no transient Field. Yay!
    

    无论您考虑什么,首先检查您的本机 API 是否不必要地闲聊,否则您的 GC 会受到影响。

    干杯, 弗洛里安

    【讨论】:

      【解决方案3】:

      如果您要管理所有语言之间的多个复杂调用,我建议使用一个抽象层来分离所有调用。

      我在相同的情况下成功地使用了 CORBA 和 XML-RPC,两者都得到了很好的支持/记录。 但它们各有利弊,您将在选择一之前学习。

      【讨论】:

        【解决方案4】:

        有很多比较 C/C++ 和 Java 的基准。 (第二个也包括C#) 注意:这些只是基准,应谨慎使用。

        http://www.idiom.com/~zilla/Computer/javaCbenchmark.html
        http://reverseblade.blogspot.com/2009/02/c-versus-c-versus-java-performance.html

        与通过转换层相比,在一个环境中执行所有操作总是更快。当然,如果您开始进行远程调用,它总是会慢很多。如果你要串话,这个想法是保持高粒度。

        【讨论】:

          【解决方案5】:

          我没有 C# 到 Java 的指标。但是,我们有很多调用 C++ 到 Java 的经验。即使在缓存了所有类和方法 ID 之后,它也非常慢。 C++/JNI 调用似乎需要大约 1000 个时钟周期,我们观察到大约 3M 调用/秒作为限制。因此,我们经历了多次优化迭代,包括一次调用将数据块传输到 Java。此外,您必须检查 Java 异常或至少在返回时重置异常状态,这又增加了一点开销。

          另一方面,从 Java 调用 C++ 非常快。如果你能做到这一点,那就去做吧。有一些高级技术涉及 Java 和 C++ 反转控制的“延续”。它是这样的:

          C++ -> Java: Start the continuation loop
             Java: while some condition
                Java -> C++: What do you want me to do
                C++: please do this action for me
                Java does the action
          

          这种控制反转不适用于许多(大多数?)应用程序,但这是另一个想法。您也可以考虑各种 RPC 方法,但这些方法也往往会相当缓慢地达到最大值(1M/秒左右)。

          【讨论】:

            【解决方案6】:

            在 Mac 上调用 C# 代码的计划是什么?或者您会在 Mac 上使用 Java,在 Windows 上使用 C#?只是对您愿意承担的支持要求感到好奇。我希望从非托管 C++ 调用托管 C++ 会相当有效,但我承认我从未这样做过。

            【讨论】:

            • 基本上要么我们使用 Java API 并且支持 Windows 和 Mac,要么我们使用 C# 并且只支持 Windows。客户希望启用 Mac 支持,但性能优先于环境。
            • 至少在 .Net 1.0、1.1 和 2.0 时代,CLR 和命令行 (csc) 编译器可以下载用于 Mac。除了 System.Windows.Form.* 之外的所有内容都可用。
            猜你喜欢
            • 2010-12-31
            • 2010-12-14
            • 2018-09-27
            • 2010-09-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多