从Java调用本机代码的最佳实践

时间:2015-10-31 19:45:56

标签: java java-native-interface jna

我打算将我的Java代码中的一些热点替换为本机(可能是C ++,但仍有待决定)。如何做到这一点的现代选择是什么? (我不打算或想要移植整个应用程序)。

我可以使用例如:

  • JNI
  • JNA
  • 将本机作为一个单独的进程生成,然后使用以下方式进行通信:
    • TCP
    • UDP
    • 共享内存
    • 标准输入/输出
    • ZeroMQ ..

我在这方面有完全的自由。是否有推荐的最佳实践方法?

2 个答案:

答案 0 :(得分:0)

这是一个非常广泛的问题。最好的做法是根据每个"热点"而不同。您的系统有,以及您可以使用哪些替代方案进行本机处理。

例如,在我使用的Java应用程序中,我们有几个图形处理部分,包括从一种格式到另一种格式的转换。虽然第三方Java库确实存在并且我已经测试了几个,但是我还没有找到一个像我通过JNI访问的C ++库那样将PDF转换为TIFF的高效和准确。为什么JNI超过JNA?性能基于我们测试的版本;通过JNI代码访问具有更快的吞吐量。这可能不适用于所有应用程序,但它确实适用于我的实现。

您的热点可能仅仅是您的编码架构的问题,并且只需要在Java中进行一些调查和重构,而不需要任何本机替换。

我重构的一个应用程序以程序方式执行了几项任务。即使多线程整个过程也无法正常工作。我将程序分解为8个不同的阶段,并确定了瓶颈,然后由多线程工作队列处理。现在系统运行效率很高,仍然是100%Java。

与非Java应用程序的通信还取决于非Java应用程序接受该通信的工具。我曾经使用Runtime.exec()来生成本机进程,将数据文件放在文件夹中进行外部处理,并调用Web服务。 "本地人"解决方案实际上取决于(1)您可用的本机资源是什么,(2)哪种本地资源最适合处理此问题"热点"用例,以及(3)可用于所述本机资源的可访问性。即便如此,重构现有代码可能仍然是最好的选择。

重申:任何给定的热点"可能是由于许多因素造成的,每个因素都需要个别关注,而这里无法提供广泛的答案。您最好的选择是识别每个热点",并分别评估它们如何最佳地优化它们;如有必要,请提出一个热点"特定问题来处理它。

答案 1 :(得分:0)

如果函数相当短(~毫秒或更短),进程内可能是唯一合理的选择。 (运行单独的进程时,每次调用的上下文切换延迟可能超过执行时间)。

JNI 是一个可移植的 API 层,是事实上的标准;然而,原始 JNI 并不容易使用。 JNA 在底层使用了 JNI,但它的级别更高,更易于使用,而且相当流行。这可能是你最安全的赌注。你也可以考虑https://github.com/dejwk/janet(我写的);它也在底层使用了 JNI,但我认为它比 JNA 更容易使用。