跨语言编程

30 6月

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: 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/

发表回复

您的电子邮箱地址不会被公开。