Для чего нужна данная статья? :
Написать видеосервер с ML
Найти компромиссы между разными способами взаимодействия Rust и C#:
1. Через динамическую библиотеку (DLL/SO/DYLIB)
- Напишите библиотеку на Rust и скомпилируйте её в динамическую библиотеку (.dll на Windows, .so на Linux, .dylib на macOS).
- В C# используйте атрибут [DllImport] из пространства имен System.Runtime.InteropServices для вызова функций из библиотеки.
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
a + b
}
C#:
using System.Runtime.InteropServices;
class Program {
[DllImport("mylib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int add(int a, int b);
static void Main() {
int result = add(2, 3);
Console.WriteLine($"Result: {result}");
}
}
2. Через статическую библиотеку
- Rust код компилируется в статическую библиотеку (.lib на Windows, .a на Linux/macOS).
- Затем C# код подключается через промежуточный C/C++ слой с использованием P/Invoke.
#[no_mangle]
pub extern "C" fn multiply(a: i32, b: i32) -> i32 {
a * b
}
C++ (промежуточный слой):
extern "C" int multiply(int a, int b);
C#:
Используйте [DllImport] для вызова C++ обёртки.
3. Через C API
- Rust библиотека предоставляет интерфейс C API.
- В C# можно использовать P/Invoke для вызова функций из Rust, которые экспортируются как extern "C".
Пример похож на подход через DLL, но сосредоточен на создании C-совместимого интерфейса.
4. Через cbindgen для автоматической генерации C-заголовков
- Эти заголовки упрощают интеграцию Rust в C# через промежуточный слой или P/Invoke.
5. Через FFI с библиотекой UnmanagedExports
- Вы можете использовать библиотеку UnmanagedExports в C#, чтобы экспортировать функции как интерфейс для взаимодействия с Rust.
6. Через COM (Component Object Model)
- Напишите Rust-код, который реализует COM-интерфейс.
- В C# можно подключаться к COM-объекту, используя встроенные средства .NET для работы с COM.
7. Через межпроцессное взаимодействие (IPC)
- Если прямое взаимодействие не требуется, можно использовать протоколы межпроцессного взаимодействия, такие как:gRPC
REST API (с помощью веб-сервера на Rust, например Actix Web или Axum)
Unix/Pipe-сокеты
Это полезно, если C# и Rust выполняются в разных процессах.
8. Через .NET Native (с помощью Rust + C# mixed code)
- Экспериментальный подход с использованием interop библиотек, где вы пишете код для взаимодействия напрямую через платформу Windows (Windows Metadata).
9. Через wasm
- Скомпилируйте Rust в WebAssembly (WASM) и выполните его в среде, поддерживаемой .NET. Например, с Blazor или другим движком WebAssembly в C#.
10. Через Cxx и CxxSharp
- Затем подключите этот C++ слой в C# с помощью P/Invoke.
Зачем Вам это уметь? :
Обезопасить память используя Rust библиотеки.
Использовать Rust для создания безопасного программного обеспечения, включая криптографические алгоритмы и протоколы.
Написание надежного конкурентного кода.
Использовать библиотеки работающее на разных платформах, включая Windows, macOS, Linux, и веб (через WebAssembly).
Видеосервер C# + Rust + ML
Принимает видеопоток WebRTC
Обрабатывает кадры с YOLOv8 + OpenCV
Ускорение через CUDA или wgpu
Поддержка RabbitMQ для распределённой обработки.
use tokio::sync::mpsc;
use opencv::{prelude::*, videoio, objdetect, core};
use webrtc::peer_connection::RTCPeerConnection;
use std::sync::Arc;
use tch::{CModule, Tensor, Device};
use lapin::{options::*, types::FieldTable, Connection, ConnectionProperties, Channel};
use tonic::transport::Server;
use grpc::video_processing::{video_processor_server::{VideoProcessor, VideoProcessorServer}, ProcessRequest, ProcessResponse};
use std::time::Instant;
#[tokio::main]
async fn main() {
println!("Инициализация системы...");
println!("Используемый GPU: {:?}", Device::cuda_if_available());
let rtc_conn = setup_webrtc().await.unwrap();
let channel = setup_rabbitmq().await.unwrap();
tokio::spawn(start_grpc_server());
println!("Запуск обработки видео...");
process_video(rtc_conn, channel).await;
}
async fn setup_webrtc() -> Result<Arc<RTCPeerConnection>, Box<dyn std::error::Error>> {
let config = webrtc::peer_connection::configuration::RTCConfiguration::default();
let peer_connection = webrtc::api::APIBuilder::new().build().new_peer_connection(config).await?;
Ok(Arc::new(peer_connection))
}
async fn setup_rabbitmq() -> Result<Channel, Box<dyn std::error::Error>> {
let conn = Connection::connect("amqp://localhost:5672", ConnectionProperties::default()).await?;
let channel = conn.create_channel().await?;
Ok(channel)
}
async fn process_video(rtc_conn: Arc<RTCPeerConnection>, channel: Channel) {
let capture = videoio::VideoCapture::new(0, videoio::CAP_ANY).unwrap();
let mut frame = Mat::default();
let model = CModule::load("yolov8.pt").unwrap();
loop {
let start = Instant::now();
capture.read(&mut frame).unwrap();
detect_objects(&frame, &model);
let duration = start.elapsed();
println!("Время обработки кадра: {:?}", duration);
}
}
fn detect_objects(frame: &Mat, model: &CModule) {
let tensor = Tensor::from_data(frame.data_bytes().unwrap()).to_device(Device::cuda_if_available());
let output = model.forward(&[tensor]).unwrap();
println!("Обнаруженные объекты: {:?}", output);
}
async fn start_grpc_server() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let video_processor = VideoProcessorService {};
Server::builder().add_service(VideoProcessorServer::new(video_processor)).serve(addr).await?;
Ok(())
}
struct VideoProcessorService;
#[tonic::async_trait]
impl VideoProcessor for VideoProcessorService {
async fn process(&self, request: tonic::Request<ProcessRequest>) -> Result<tonic::Response<ProcessResponse>, tonic::Status> {
println!("Получен gRPC-запрос на обработку видео");
Ok(tonic::Response::new(ProcessResponse { success: true }))
}
}
Здесь setup_webrtc настраивает соединение для видеосвязи, но не блокирует остальной код. Запускает функцию в отдельном потоке, чтобы она работала параллельно с остальным кодом.
- VideoCapture — захват видео с камеры.
- Mat — изображение (кадр видео).
- CModule — загруженная модель нейросети (например, для распознавания объектов).
- Tensor — данные, которые нейросеть обрабатывает (например, изображение).