polyglot-integration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Polyglot Integration

多语言集成

Overview

概述

Integrate code written in different programming languages to leverage their unique strengths and ecosystems.
集成使用不同编程语言编写的代码,以利用它们各自独特的优势和生态系统。

When to Use

适用场景

  • Performance-critical code in C/C++/Rust
  • ML models in Python from other languages
  • Legacy system integration
  • Leveraging language-specific libraries
  • Microservices polyglot architecture
  • 用C/C++/Rust编写性能关键型代码
  • 在其他语言中调用Python的ML模型
  • 遗留系统集成
  • 利用特定语言的库
  • 微服务多语言架构

Implementation Examples

实现示例

1. Node.js Native Addons (C++)

1. Node.js 原生扩展(C++)

cpp
// addon.cc
#include <node.h>

namespace demo {

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Number;

void Add(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  if (args.Length() < 2) {
    isolate->ThrowException(v8::Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }

  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(v8::Exception::TypeError(
        String::NewFromUtf8(isolate, "Arguments must be numbers")));
    return;
  }

  double value = args[0]->NumberValue() + args[1]->NumberValue();
  Local<Number> num = Number::New(isolate, value);

  args.GetReturnValue().Set(num);
}

void Initialize(Local<Object> exports) {
  NODE_SET_METHOD(exports, "add", Add);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

}
javascript
// Usage in Node.js
const addon = require('./build/Release/addon');
console.log(addon.add(3, 5)); // 8
cpp
// addon.cc
#include <node.h>

namespace demo {

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Number;

void Add(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  if (args.Length() < 2) {
    isolate->ThrowException(v8::Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }

  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(v8::Exception::TypeError(
        String::NewFromUtf8(isolate, "Arguments must be numbers")));
    return;
  }

  double value = args[0]->NumberValue() + args[1]->NumberValue();
  Local<Number> num = Number::New(isolate, value);

  args.GetReturnValue().Set(num);
}

void Initialize(Local<Object> exports) {
  NODE_SET_METHOD(exports, "add", Add);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

}
javascript
// Usage in Node.js
const addon = require('./build/Release/addon');
console.log(addon.add(3, 5)); // 8

2. Python from Node.js

2. 从Node.js调用Python

typescript
// Using child_process
import { spawn } from 'child_process';

function callPython(script: string, args: any[] = []): Promise<any> {
  return new Promise((resolve, reject) => {
    const python = spawn('python3', [script, ...args.map(String)]);

    let stdout = '';
    let stderr = '';

    python.stdout.on('data', (data) => {
      stdout += data.toString();
    });

    python.stderr.on('data', (data) => {
      stderr += data.toString();
    });

    python.on('close', (code) => {
      if (code !== 0) {
        reject(new Error(stderr));
      } else {
        try {
          resolve(JSON.parse(stdout));
        } catch (error) {
          resolve(stdout);
        }
      }
    });
  });
}

// Usage
const result = await callPython('./ml_model.py', [100, 200]);
console.log('Python result:', result);
python
undefined
typescript
// Using child_process
import { spawn } from 'child_process';

function callPython(script: string, args: any[] = []): Promise<any> {
  return new Promise((resolve, reject) => {
    const python = spawn('python3', [script, ...args.map(String)]);

    let stdout = '';
    let stderr = '';

    python.stdout.on('data', (data) => {
      stdout += data.toString();
    });

    python.stderr.on('data', (data) => {
      stderr += data.toString();
    });

    python.on('close', (code) => {
      if (code !== 0) {
        reject(new Error(stderr));
      } else {
        try {
          resolve(JSON.parse(stdout));
        } catch (error) {
          resolve(stdout);
        }
      }
    });
  });
}

// Usage
const result = await callPython('./ml_model.py', [100, 200]);
console.log('Python result:', result);
python
undefined

ml_model.py

ml_model.py

import sys import json
def predict(x, y): # ML model logic return x * 2 + y
if name == 'main': x = int(sys.argv[1]) y = int(sys.argv[2]) result = predict(x, y) print(json.dumps({'prediction': result}))
undefined
import sys import json
def predict(x, y): # ML model logic return x * 2 + y
if name == 'main': x = int(sys.argv[1]) y = int(sys.argv[2]) result = predict(x, y) print(json.dumps({'prediction': result}))
undefined

3. Rust from Python (PyO3)

3. 从Python调用Rust(PyO3)

rust
// lib.rs
use pyo3::prelude::*;

#[pyfunction]
fn fibonacci(n: u64) -> PyResult<u64> {
    let mut a = 0;
    let mut b = 1;

    for _ in 0..n {
        let temp = a;
        a = b;
        b = temp + b;
    }

    Ok(a)
}

#[pyfunction]
fn process_large_array(arr: Vec<f64>) -> PyResult<f64> {
    Ok(arr.iter().sum())
}

#[pymodule]
fn rust_extension(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(fibonacci, m)?)?;
    m.add_function(wrap_pyfunction!(process_large_array, m)?)?;
    Ok(())
}
python
undefined
rust
// lib.rs
use pyo3::prelude::*;

#[pyfunction]
fn fibonacci(n: u64) -> PyResult<u64> {
    let mut a = 0;
    let mut b = 1;

    for _ in 0..n {
        let temp = a;
        a = b;
        b = temp + b;
    }

    Ok(a)
}

#[pyfunction]
fn process_large_array(arr: Vec<f64>) -> PyResult<f64> {
    Ok(arr.iter().sum())
}

#[pymodule]
fn rust_extension(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(fibonacci, m)?)?;
    m.add_function(wrap_pyfunction!(process_large_array, m)?)?;
    Ok(())
}
python
undefined

Usage in Python

Usage in Python

import rust_extension
result = rust_extension.fibonacci(100) print(f"Fibonacci: {result}")
arr = list(range(1000000)) total = rust_extension.process_large_array(arr) print(f"Sum: {total}")
undefined
import rust_extension
result = rust_extension.fibonacci(100) print(f"Fibonacci: {result}")
arr = list(range(1000000)) total = rust_extension.process_large_array(arr) print(f"Sum: {total}")
undefined

4. gRPC Polyglot Communication

4. gRPC多语言通信

protobuf
// service.proto
syntax = "proto3";

service Calculator {
  rpc Add (NumberPair) returns (Result);
  rpc Multiply (NumberPair) returns (Result);
}

message NumberPair {
  double a = 1;
  double b = 2;
}

message Result {
  double value = 1;
}
python
undefined
protobuf
// service.proto
syntax = "proto3";

service Calculator {
  rpc Add (NumberPair) returns (Result);
  rpc Multiply (NumberPair) returns (Result);
}

message NumberPair {
  double a = 1;
  double b = 2;
}

message Result {
  double value = 1;
}
python
undefined

Python gRPC Server

Python gRPC Server

import grpc from concurrent import futures import service_pb2 import service_pb2_grpc
class Calculator(service_pb2_grpc.CalculatorServicer): def Add(self, request, context): return service_pb2.Result(value=request.a + request.b)
def Multiply(self, request, context):
    return service_pb2.Result(value=request.a * request.b)
def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) service_pb2_grpc.add_CalculatorServicer_to_server(Calculator(), server) server.add_insecure_port('[::]:50051') server.start() server.wait_for_termination()
if name == 'main': serve()

```typescript
// Node.js gRPC Client
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';

const packageDefinition = protoLoader.loadSync('service.proto');
const proto = grpc.loadPackageDefinition(packageDefinition);

const client = new proto.Calculator(
  'localhost:50051',
  grpc.credentials.createInsecure()
);

client.Add({ a: 10, b: 20 }, (error, response) => {
  if (error) {
    console.error(error);
  } else {
    console.log('Result:', response.value);
  }
});
import grpc from concurrent import futures import service_pb2 import service_pb2_grpc
class Calculator(service_pb2_grpc.CalculatorServicer): def Add(self, request, context): return service_pb2.Result(value=request.a + request.b)
def Multiply(self, request, context):
    return service_pb2.Result(value=request.a * request.b)
def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) service_pb2_grpc.add_CalculatorServicer_to_server(Calculator(), server) server.add_insecure_port('[::]:50051') server.start() server.wait_for_termination()
if name == 'main': serve()

```typescript
// Node.js gRPC Client
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';

const packageDefinition = protoLoader.loadSync('service.proto');
const proto = grpc.loadPackageDefinition(packageDefinition);

const client = new proto.Calculator(
  'localhost:50051',
  grpc.credentials.createInsecure()
);

client.Add({ a: 10, b: 20 }, (error, response) => {
  if (error) {
    console.error(error);
  } else {
    console.log('Result:', response.value);
  }
});

5. Java from Python (Py4J)

5. 从Python调用Java(Py4J)

java
// JavaApp.java
public class JavaApp {
    public int add(int a, int b) {
        return a + b;
    }

    public String processData(String data) {
        return data.toUpperCase();
    }

    public static void main(String[] args) {
        JavaApp app = new JavaApp();
        GatewayServer server = new GatewayServer(app);
        server.start();
    }
}
python
undefined
java
// JavaApp.java
public class JavaApp {
    public int add(int a, int b) {
        return a + b;
    }

    public String processData(String data) {
        return data.toUpperCase();
    }

    public static void main(String[] args) {
        JavaApp app = new JavaApp();
        GatewayServer server = new GatewayServer(app);
        server.start();
    }
}
python
undefined

Python client

Python client

from py4j.java_gateway import JavaGateway
gateway = JavaGateway() app = gateway.entry_point
result = app.add(10, 20) print(f"Result: {result}")
processed = app.processData("hello world") print(f"Processed: {processed}")
undefined
from py4j.java_gateway import JavaGateway
gateway = JavaGateway() app = gateway.entry_point
result = app.add(10, 20) print(f"Result: {result}")
processed = app.processData("hello world") print(f"Processed: {processed}")
undefined

Best Practices

最佳实践

✅ DO

✅ 建议

  • Use appropriate IPC mechanism
  • Handle serialization carefully
  • Implement proper error handling
  • Consider performance overhead
  • Use type-safe interfaces
  • Document integration points
  • 使用合适的IPC机制
  • 谨慎处理序列化
  • 实现完善的错误处理
  • 考虑性能开销
  • 使用类型安全的接口
  • 记录集成点

❌ DON'T

❌ 避免

  • Pass complex objects across boundaries
  • Ignore memory management
  • Skip error handling
  • Use blocking calls in async code
  • 在边界之间传递复杂对象
  • 忽略内存管理
  • 跳过错误处理
  • 在异步代码中使用阻塞调用

Integration Methods

集成方法

MethodUse CaseOverhead
Native BindingsPerformance-critical codeLow
IPC/PipesSeparate processesMedium
gRPCMicroservicesMedium
HTTP/RESTLoose couplingHigh
Message QueueAsync processingMedium
方法适用场景开销
原生绑定性能关键型代码
IPC/管道独立进程
gRPC微服务
HTTP/REST松耦合
消息队列异步处理

Resources

参考资源