简体   繁体   English

用Java重写C代码还是使用JNI?

[英]Rewrite C code in Java or use JNI?

I'm currently developing on a project written in Java. 我目前正在开发一个用Java编写的项目。 We have a bunch of algorithms written in C/C++ (at least a couple hundred) that need to be incorporated in our project. 我们有一堆用C / C ++编写的算法(至少几百个)需要合并到我们的项目中。 Our two options are to use JNI to call this code, or to rewrite all the algorithms in Java. 我们的两个选择是使用JNI来调用此代码,或者用Java重写所有算法。

I am aware of the consequences of using JNI, it can open up a whole new set of problems, which is why rewriting all the code in Java is even being considered. 我知道使用JNI的后果,它可以打开一组全新的问题,这就是为什么用Java重写所有代码甚至被考虑的原因。 But the thought of rewriting it seems...wrong. 但重写它的想法似乎......错了。 The algorithms have been tested and work as far as I know, they're just in the wrong language. 据我所知,算法已经过测试和工作,它们只是用错了语言。

In this situation, would JNI make this task easy? 在这种情况下,JNI能否轻松完成这项任务? Or would it cause more headache than rewriting the code in Java would? 或者它会比重写Java中的代码更令人头痛吗?


EDIT #1: Related Question - Usefulness of JNI 编辑#1:相关问题 - JNI的用处


EDIT #2: FYI - Our Java project is not meant to be portable in any way. 编辑#2:仅供参考 - 我们的Java项目无意以任何方式移植。 That might eliminate one of the downsides of JNI in that it supposedly reduces portability. 这可能会消除JNI的一个缺点,因为它可能会降低可移植性。

The simple answer is, if the code is going to be called a lot AND performance matters then convert it over to Java. 简单的答案是,如果代码将被调用很多并且性能很重要,那么将其转换为Java。

The more complex answers are: 更复杂的答案是:

  • if the library easily wrapped in JNI then go with JNI 如果库容易包装在JNI中,那么请使用JNI
  • if the tests you have for the C/C++ code easily converted over to Java then go for the port 如果您对C / C ++代码的测试很容易转换为Java,那么请转到端口

I would do the following: 我会做以下事情:

  • take one of the algorithms and wrap it in JNI 采用其中一种算法并将其包装在JNI中
  • take the same algorithm and convert it to Java 采用相同的算法并将其转换为Java
  • see which is more of a pain to do 看看哪个更痛苦
  • if speed matters then profile both versions and see which of them is acceptable. 如果速度很重要,那么对两个版本进行分析,看看哪些版本是可以接

I think the answer lies in the amount of coupling there would be between the calling java code and the invoked C/C++ code and in the level of effort the rewrite would entail. 我认为答案在于调用java代码和调用的C / C ++代码之间的耦合量以及重写所需的工作量。 If your C code takes a few integers, does some hairy calculation, and returns another int. 如果你的C代码需要几个整数,那么就做一些毛茸茸的计算,并返回另一个int。 Use JNI. 使用JNI。 If there's a lot of complex back and forth, but the algorithms are reasonably simple, rewrite 'em. 如果有很多复杂的来回,但算法相当简单,重写'em。 The fault line is the JNI connection. 故障线是JNI连接。 If that's going to be complex, you may end up writing more JNI interface code than you would algorithm code for a rewrite. 如果这将变得复杂,您最终可能会编写更多的JNI接口代码而不是算法代码进行重写。

If the "algorithms" are well-packaged, perhaps it's possible to create some automatic glue code, through JNI? 如果“算法”包装得很好,也许可以通过JNI创建一些自动胶水代码? That would cut down on the risk of errors (creating hundreds of individual components manually sounds risky), and make the cost independent of the number of algorithms to add, more or less. 这样可以减少错误的风险(手动创建数百个单独的组件听起来很冒险),并且使成本与要添加的算法数量无关,或多或少。

Rewriting hundreds of components sounds very risky, I would definitely recommend at least investigating JNI more closely first. 重写数百个组件听起来非常危险,我肯定会建议至少首先更密切地调查JNI。

What I/O requirements do the algorithms have with respect to the rest of the project? 算法对项目的其余部分有哪些I / O要求? If they are fairly loosely coupled, perhaps it'd be possible to run them as free-standing separate programs, invoked as sub-processes from Java and using eg stdio to share data? 如果它们相当松散耦合,也许可以将它们作为独立的独立程序运行,从Java调用子流程并使用例如stdio来共享数据?

I think you'll find that using JNI is not as daunting as it seems prior to diving in. There are some important trade-offs and limitations but in general JNI works well and is reasonably easy to leverage as you intend. 我认为你会发现使用JNI并不像潜水之前那样令人生畏。有一些重要的权衡和限制,但总的来说JNI效果很好,并且很容易按照你的意愿来利用。

As other have said the best case for JNI is: 正如其他人所说,JNI的最佳案例是:

  • Complex native code (bonus points if that code has already proven very reliable) 复杂的原生代码(如果该代码已被证明非常可靠,则可获得奖励积分
  • Minimal back-and-forth between Java and native code (you want to minimize the trips across the JNI layer) Java和本机代码之间的最小来回(您希望最小化跨JNI层的行程)
  • Reasonably simple calling interface to the native code (or also back to Java if you're native code needs to leverage Java objects/methods) 对本机代码的调用接口相当简单(如果本机代码需要利用Java对象/方法,也可以返回Java)

It is definitely possible to automate or pseudo-automate the creation of a JNI layer for a reasonably structured set of native components. 绝对有可能为一组合理结构的本机组件自动化或伪自动化创建JNI层。 That would be well worth it if the number of components to wrap is large. 如果要换行的组件数量很大,那将是非常值得的。

The good news with JNI is that it should be straightforward for you to build and test this interface, for example you should be able to write test cases from Java that exploit existing algorithm behavior and if there are problems they would most likely be in the JNI layer itself and not the algorithms (given your confidence in the native implementation). JNI的好消息是,您应该直接构建和测试此接口,例如,您应该能够从Java编写利用现有算法行为的测试用例,如果有问题,他们很可能会在JNI中图层本身而不是算法(鉴于您对本机实现的信心)。

Rewriting a large number of C/C++ algorithms in Java seems much more risky to me than using JNI. 用Java重写大量的C / C ++算法似乎比使用JNI风险更大。 Without knowing the details it is hard to gauge, of course, but there are subtle differences between the technologies that I could imagine impacting the actual implementation of an algorithm, not to mention just the sheer engineering effort and risk of error. 当然,在不了解细节的情况下很难衡量,但我认为影响算法实际实现的技术之间存在细微差别,更不用说纯粹的工程工作和错误风险。

A final consideration is future life of these algorithms or related components. 最后的考虑因素是这些算法或相关组件的未来生命。 Is the set of algorithms more or less complete, or are you continuing to add? 算法集是或多或少完整,或者您是否继续添加? Either way, is there a strong maintenance and/or future development reason to favor one technology over the other? 无论哪种方式,是否有强大的维护和/或未来的发展理由支持一种技术而不是另一种? For example, if everything else is in Java and all new algorithms will be in Java and almost everyone on the team is almost always coding in Java, reimplementing in Java starts to look more attractive long-term. 例如,如果其他所有内容都使用Java,并且所有新算法都使用Java,并且团队中的每个人几乎总是使用Java进行编码,那么Java中的重新实现开始看起来更具吸引力。

However even with that said, working trumps consistent. 然而即便如此,工作胜过一致。 For a large number of well-functioning native components I would still be inclined to start with JNI even if you were going to transition to Java long-term. 对于大量运行良好的本机组件,即使您要长期过渡到Java,我仍然倾向于从JNI开始。

I'd still seriously consider going for JNI, particularly if you're able to minimize the number of cross-language interfaces. 我仍然认真考虑选择JNI,特别是如果你能够最小化跨语言接口的数量。

If, for example, there's a whole stack of C functions that all have the same inputs and outputs, but just do different work on the inputs, wrap that up in a single JNI wrapper with an additional parameter to specify which specific algorithm to use. 例如,如果有一堆C函数都具有相同的输入和输出,但只是对输入做了不同的工作,请将其包含在一个带有附加参数的JNI包装器中,以指定要使用的特定算法。

If you plan to write future projects in Java, as opposed to C/C++. 如果您打算用Java编写未来的项目,而不是C / C ++。 I would bite the bullet now, and port the code over to java. 我现在会咬紧牙关,将代码移植到java。 The longer you wait the worse it will become. 你等待的时间越长,它就越糟糕。 The JNI sounds attractive in this case, but then you will have the problem of somebody having to maintain the C++ code when everyone else is on the fun new Java projects. 在这种情况下,JNI听起来很有吸引力,但是当其他人都在有趣的新Java项目上时,你会遇到有人必须维护C ++代码的问题。

If this is a one time Java project, then why are you writing it in Java? 如果这是一次性Java项目,那么为什么要用Java编写它?

The bridge between C and Java is expensive, so if you have to pass a lot of data back and forth there is no win in calling C over JNI. C和Java之间的桥梁很昂贵,所以如果你必须来回传递大量数据,那么通过JNI调用C就没有胜利。

I have seen JNA listed as a reasonable alternative to JNI with a lot less pain to call methods in a DLL/shared library from Java in a reflection like way. 我已经看到JNA被列为JNI的合理替代品,并且以类似的方式从Java调用DLL /共享库中的方法的痛苦要小得多。 I have not tried it yet. 我还没有尝试过。

You may want to consider compiling your C code as a Linux MIPS binary which can be interpreted in Java. 您可能需要考虑将C代码编译为可以用Java解释的Linux MIPS二进制文件。 Reasonably fast, a bit hard to set up correctly. 合理快速,有点难以正确设置。 See http://nestedvm.ibex.org/ http://nestedvm.ibex.org/

Also you may use a llvm backend to gcc to compile to lowlevel bytecodes which can then be interpreted in Java. 您也可以使用llvm后端来gcc编译为低级字节码,然后可以用Java解释。 THis is also the approach taken with the iPhone SDK afaik on Mac OS X. http://llvm.org/ 这也是在Mac OS X上使用iPhone SDK的方法.http://llvm.org/

Read Joel's receint post on " Paying down your technical debt " then go ahead and convert it now rather than pay interest over the next couple years and then paying it off. 阅读乔尔关于“ 降低技术债务 ”的评论帖,然后继续转换,而不是在未来几年支付利息,然后付清。

Perhaps the repackaged libraries could be useful in more places as well. 也许重新打包的库也可以在更多地方使用。 If they are useful and complex enough to make you consider keeping them in C, they must have even more use once packaged nicely in reusable, easily distributable and understandable classes. 如果它们有用且复杂到足以让你考虑将它们保存在C中,那么一旦在可重用,易于分发和可理解的类中很好地打包它们,它们必须具有更多的用途。

I've been in this situation. 我一直在这种情况下。 I suggest that you get used to using the multi-threaded data structures that are available in Java. 我建议您习惯使用Java中提供的多线程数据结构。 At this point you won't want to go back to your C++ data structures any more. 此时,您将不再需要返回到C ++数据结构。

You'll also realize that you can re-write those algorithms much better using more thoughtful techniques, better polymorphism, adapter patterns and so forth. 您还将意识到,您可以使用更周到的技术,更好的多态性,适配器模式等来更好地重写这些算法。

When you're sitting in the C/C++ code, you're thinking that you want to hang on to it. 当你坐在C / C ++代码中时,你认为你想要坚持下去。 You're thinking about all the love you put into it. 你正在考虑你投入的所有爱。 In a few years, you'll realize that by holding onto it and using JNI that you've created a monster. 几年后,你会意识到通过坚持并使用JNI你已经创造了一个怪物。 Every time you get a process crash you'll regret using JNI. 每当你遇到进程崩溃时,你都会后悔使用JNI。 After fixing the process crash, someone will want to modify an algorithm in C++ and you'll want to throttle them. 在修复进程崩溃后,有人会想要在C ++中修改算法,你会想要限制它们。 They'll have a convenient excuse like "I'm not used to Java yet." 他们会有一个方便的借口,比如“我还不习惯Java。”

Take a look at immutable data structures in Java. 看看Java中的不可变数据结构。 Don't even think about the speed that these old C/C++ algorithms execute. 甚至不要考虑这些旧的C / C ++算法执行的速度。 I've found that my new code far out-paces any of my old C/C++ code. 我发现我的新代码远远超过了我的旧C / C ++代码。

Write unit tests. 写单元测试。 Use NetBeans. 使用NetBeans。

Kind Regards, 亲切的问候,

-Stosh -Stosh

Give JNI a try. 试试JNI吧。 Then if faced with any problems you may rewrite the problematic ones or wrap JNI calls with webservices and deploy them on different boxes or virtual boxes. 然后,如果遇到任何问题,您可以重写有问题的问题,或者使用webservices包装JNI调用,并将它们部署在不同的盒子或虚拟盒子上。

If this is Windows-only, and they're already in a DLL, perhaps JNA would be of use. 如果这只是Windows,并且它们已经在DLL中,那么JNA可能会被使用。 (if the performance hit for function calls through JNA isn't too bad) (如果通过JNA调用函数的性能不是太差)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM