本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
转载自夜明的孤行灯
本文链接地址: https://www.huangyunkun.com/2022/06/30/cross-lang-call/
日常工作中由于公司业务和IT资产的原因,可能并没有接触到这块。但是跨语言编程是现代程序语言中非常重要的一个方向,也被广泛应用于复杂系统的设计与实现中。
场景
跨语言可以用于很多场景,但是常用的有以下几种
基于系统级语言实现系统的关键路径
一些高级语言或者说脚本语言受限于封装的运行环境,对于一些系统操作比较困难,也就是底层能力比较弱,在和操作系统或者硬件打交道的时候更多的是基于C/C++此类系统级语言去进行这次底层操作。上层语言直接调用。
依赖当前语言不支持的能力
不同语言都有适用的领域,也有能力的上限。比如早期的Java对于线程以下操作比较弱,相关API不完善,直接依赖其他语言开发的封装层更容易操作。
复用库和业务方法
这个场景的情况最多,这个有可能公司遗留遗产,也可能是公司其他系统的核心二次封装成SDK给其他部门调用。也可能是成熟开源库在当前语言没有替代品,比如在java中使用opencv。
复用不一定是为了业务功能,很多时候也处于性能考虑,在特定场景特定语言优势比较明显,比如矩阵操作等。
原理
跨语言调用方法一就是RPC调用,通过网络端口提供服务,并通过约定的请求格式进行通讯。这个方法简单成熟,非常适合不同语言负责的是不同领域的场合。比如一个帮助系统(Python),调用一个自然语言处理模块(C++)进行分词等操作。由于基于RPC通讯,双方本质上只依赖于协议,具体实现解耦。方便扩展更多语言的调用方,也方便双方独立升级。
另外一种更紧密的结合就是在同一个CPU运行,不管语言、环境等等花里胡哨的东西,最后都要走到CPU执行指令这里。这里细分两种,一种是中间代码是相同的,那么他们就通过编译工具进行融合,比如LLVM IR。更宽泛的调用时基于FFI,只要ABI时相同或者兼容的。
虽然原理类似,具体落实在使用上,每种语言使用的具体技术工具可以不同,比如Java中JNI就是Java调用的C的,而Golang可以使用CGO。
实践
常见的组合很多,这里看下Java+C和Flutter+Rust。这两种组合也恰好代表了两种使用场景。一般来说Java和C混合编程多是出于性能上的考虑,而Flutter+Rust的组合更多是出于复用逻辑的考虑。
Java+C
基于JNI可以实现这点,但是JNA框架可以更方便完成这个事情。
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.6.0</version>
</dependency>
引用以来后直接根据你的依赖库就行定义就行了。
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary(
(Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
void printf(String format, Object... args);
}
LIbrary基类会默认生成INSTANCE实例,直接调用接口。
Flutter+Rust
同样需要一个工具来生成Dart API,推荐使用flutter_rust_bridge_codegen。
参考
https://tech.meituan.com/2022/04/21/cross-language-call.html
https://xie.infoq.cn/article/3444522c1bde130f265fc4fca
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
转载自夜明的孤行灯
本文链接地址: https://www.huangyunkun.com/2022/06/30/cross-lang-call/