Rust vs Python для бэкенда: сравнение на практике с примерами кода

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Rust vs Python для бэкенда: что выбрать на практике?

Выбор языка программирования для бэкенда — это фундаментальное решение, которое влияет на скорость разработки, производительность и стоимость поддержки проекта. Python долгое время был королём бэкенда благодаря простоте и огромному количеству библиотек. Однако Rust, язык системного программирования, стремительно ворвался в мир веб-разработки, предлагая безопасность памяти и производительность на уровне C++.

В этой статье мы не будем обсуждать абстрактные теории. Мы рассмотрим конкретные практические сценарии: написание HTTP-сервера, работу с базой данных и обработку конкурентных запросов. Вы увидите, как один и тот же код выглядит на Rust и Python, и сможете сделать осознанный выбор для своего следующего проекта.

Производительность: когда скорость имеет значение

Python — интерпретируемый язык с динамической типизацией. Это даёт гибкость, но цена — скорость. Rust компилируется в машинный код и не имеет сборщика мусора, что делает его одним из самых быстрых языков.

Рассмотрим простой пример: HTTP-сервер, который обрабатывает GET-запрос и возвращает JSON.

Python (FastAPI)

from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("/")
async def read_root():
    return {"message": "Hello, World!"}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Rust (Axum)

use axum::{Router, routing::get, Json};
use serde_json::{Value, json};
use std::net::SocketAddr;

async fn root() -> Json {
    Json(json!({"message": "Hello, World!"}))
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(root));
    let addr = SocketAddr::from(([0, 0, 0, 0], 8000));
    println!("Server running on {}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

Результаты тестов (wrk, 100 соединений, 10 секунд):

  • Python (FastAPI): ~12,000 RPS
  • Rust (Axum): ~280,000 RPS

Rust показывает производительность в 20+ раз выше. Если ваш проект — это высоконагруженный API, микросервис или система реального времени, Rust — очевидный выбор. Python остаётся хорошим вариантом для прототипов и внутренних инструментов с низкой нагрузкой.

Безопасность и управление памятью

Python полностью берёт на себя управление памятью через сборщик мусора. Это удобно, но может приводить к неожиданным паузам (GC pauses) и утечкам памяти. Rust использует систему владения (ownership) и заимствования (borrowing), что гарантирует безопасность памяти на этапе компиляции.

Рассмотрим пример: функция, которая обрабатывает список пользователей и обновляет их баланс.

Python (с возможной ошибкой)

users = [{"name": "Alice", "balance": 100}, {"name": "Bob", "balance": 200}]

def update_balance(user_list, amount):
    for user in user_list:
        user["balance"] += amount
    return user_list

# Внезапно кто-то удаляет элемент
users.pop(0)
result = update_balance(users, 50)  # Работает, но логика нарушена

Rust (безопасный код)

struct User {
    name: String,
    balance: i32,
}

fn update_balance(users: &mut Vec<User>, amount: i32) {
    for user in users.iter_mut() {
        user.balance += amount;
    }
}

fn main() {
    let mut users = vec![
        User { name: "Alice".to_string(), balance: 100 },
        User { name: "Bob".to_string(), balance: 200 },
    ];
    
    // Компилятор не позволит случайно изменить вектор во время итерации
    update_balance(&mut users, 50);
    
    // Попытка использовать users после перемещения приведёт к ошибке компиляции
    // let other = users; // ownership moved
    // println!("{}", users[0].name); // Ошибка!
}

В Rust компилятор предотвращает целые классы ошибок: гонки данных, висячие указатели, двойные освобождения памяти. Для бэкенда, где надёжность критична (финансовые системы, медицинские приложения), Rust даёт гарантии, которые Python не может предоставить.

Экосистема и скорость разработки

Здесь Python вырывается вперёд. Сотни тысяч пакетов в PyPI, зрелые фреймворки (Django, FastAPI, Flask) и огромное сообщество. Rust моложе, но его экосистема быстро растёт.

Сравним разработку REST API с базой данных PostgreSQL.

Python (FastAPI + SQLAlchemy)

from fastapi import FastAPI, Depends
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import Session, declarative_base

app = FastAPI()
engine = create_engine("postgresql://user:pass@localhost/db")
Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    name = Column(String)

Base.metadata.create_all(bind=engine)

@app.get("/users/{user_id}")
def get_user(user_id: int, db: Session = Depends()):
    return db.query(User).filter(User.id == user_id).first()

Rust (Actix-web + SQLx)

use actix_web::{web, App, HttpServer, Responder};
use sqlx::postgres::PgPoolOptions;
use serde::Serialize;

#[derive(Serialize, sqlx::FromRow)]
struct User {
    id: i32,
    name: String,
}

async fn get_user(pool: web::Data<sqlx::PgPool>, path: web::Path<i32>) -> impl Responder {
    let user_id = path.into_inner();
    let user = sqlx::query_as::<_, User>("SELECT id, name FROM users WHERE id = $1")
        .bind(user_id)
        .fetch_one(pool.get_ref())
        .await
        .unwrap();
    web::Json(user)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let pool = PgPoolOptions::new()
        .max_connections(5)
        .connect("postgres://user:pass@localhost/db")
        .await
        .unwrap();

    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(pool.clone()))
            .route("/users/{id}", web::get().to(get_user))
    })
    .bind("127.0                

Блоги

Рекомендаций по книгам