Concurrency: Comparison with Other Languages

2026-08-30 浏览 (1)

Concurrency: Comparison with Other Languages

Rust vs Go

Concurrency Model

AspectRustGo
ModelOwnership + Send/SyncCSP (Communicating Sequential Processes)
PrimitivesArc, Mutex, channelsgoroutines, channels
SafetyCompile-timeRuntime (race detector)
Asyncasync/await + runtimeBuilt-in scheduler

Goroutines vs Rust Tasks

// Rust: explicit about thread safety
use std::sync::Arc;
use tokio::sync::Mutex;

let data = Arc::new(Mutex::new(vec![]));
let data_clone = Arc::clone(&data);

tokio::spawn(async move {
    let mut guard = data_clone.lock().await;
    guard.push(1);  // Safe: Mutex protects access
});

// Go: implicit sharing (potential race)
// data := []int{}
// go func() {
//     data = append(data, 1)  // RACE CONDITION!
// }()

Channel Comparison

// Rust: typed channels with ownership
use tokio::sync::mpsc;

let (tx, mut rx) = mpsc::channel::<String>(100);

tokio::spawn(async move {
    tx.send("hello".to_string()).await.unwrap();
    // tx is moved, can't be used elsewhere
});

// Go: channels are more flexible but less safe
// ch := make(chan string, 100)
// go func() {
//     ch <- "hello"
//     // ch can still be used anywhere
// }()

Rust vs Java

Thread Safety Model

AspectRustJava
SafetyCompile-time (Send/Sync)Runtime (synchronized, volatile)
NullNo null (Option)NullPointerException risk
LocksRAII (drop releases)try-finally or try-with-resources
MemoryNo GCGC with stop-the-world

Synchronization Comparison

// Rust: lock is tied to data
use std::sync::Mutex;

let data = Mutex::new(vec![1, 2, 3]);
{
    let mut guard = data.lock().unwrap();
    guard.push(4);
}  // lock released automatically

// Java: lock and data are separate
// List<Integer> data = new ArrayList<>();
// synchronized(data) {
//     data.add(4);
// }  // easy to forget synchronization elsewhere

Thread Pool Comparison

// Rust: rayon for data parallelism
use rayon::prelude::*;

let sum: i32 = (0..1000)
    .into_par_iter()
    .map(|x| x * x)
    .sum();

// Java: Stream API
// int sum = IntStream.range(0, 1000)
//     .parallel()
//     .map(x -> x * x)
//     .sum();

Rust vs C++

Safety Guarantees

AspectRustC++
Data racesPrevented at compile-timeUndefined behavior
DeadlocksNot prevented (same as C++)Not prevented
Thread safetySend/Sync traitsConvention only
Memory orderingExplicit Ordering enummemory_order enum

Atomic Comparison

// Rust: clear memory ordering
use std::sync::atomic::{AtomicI32, Ordering};

let counter = AtomicI32::new(0);
counter.fetch_add(1, Ordering::SeqCst);
let value = counter.load(Ordering::Acquire);

// C++: similar but without safety
// std::atomic<int> counter{0};
// counter.fetch_add(1, std::memory_order_seq_cst);
// int value = counter.load(std::memory_order_acquire);

Mutex Comparison

// Rust: data protected by Mutex
use std::sync::Mutex;

struct SafeCounter {
    count: Mutex<i32>,  // Mutex contains the data
}

impl SafeCounter {
    fn increment(&self) {
        *self.count.lock().unwrap() += 1;
    }
}

// C++: mutex separate from data (error-prone)
// class Counter {
//     std::mutex mtx;
//     int count;  // NOT protected by type system
// public:
//     void increment() {
//         std::lock_guard<std::mutex> lock(mtx);
//         count++;
//     }
//     void unsafe_increment() {
//         count++;  // Compiles! But wrong.
//     }
// };

Async Models Comparison

LanguageModelRuntime
Rustasync/await, zero-costtokio, async-std (bring your own)
GogoroutinesBuilt-in scheduler
JavaScriptasync/await, PromisesEvent loop (single-threaded)
Pythonasync/awaitasyncio (single-threaded)
JavaCompletableFuture, Virtual ThreadsForkJoinPool, Loom

Rust vs JavaScript Async

// Rust: async requires explicit runtime, can use multiple threads
#[tokio::main]
async fn main() {
    let results = tokio::join!(
        fetch("url1"),  // runs concurrently
        fetch("url2"),
    );
}

// JavaScript: single-threaded event loop
// async function main() {
//     const results = await Promise.all([
//         fetch("url1"),
//         fetch("url2"),
//     ]);
// }

Rust vs Python Async

// Rust: true parallelism possible
#[tokio::main(flavor = "multi_thread")]
async fn main() {
    let handles: Vec<_> = urls
        .into_iter()
        .map(|url| tokio::spawn(fetch(url)))  // spawns on thread pool
        .collect();

    for handle in handles {
        let _ = handle.await;
    }
}

// Python: asyncio is single-threaded (use ProcessPoolExecutor for CPU)
# async def main():
#     tasks = [asyncio.create_task(fetch(url)) for url in urls]
#     await asyncio.gather(*tasks)  # all on same thread

Send and Sync: Rust's Unique Feature

No other mainstream language has compile-time thread safety markers:

TraitMeaningAuto-impl
SendSafe to transfer between threadsMost types
SyncSafe to share &T between threadsTypes with thread-safe &
!SendMust stay on one threadRc, raw pointers
!SyncReferences can't be sharedRefCell, Cell

Why This Matters

// Rust PREVENTS this at compile time:
use std::rc::Rc;

let rc = Rc::new(42);
std::thread::spawn(move || {
    println!("{}", rc);  // ERROR: Rc is not Send
});

// In other languages, this would be a runtime bug:
// - Go: race detector might catch it
// - Java: undefined behavior
// - Python: GIL usually saves you
// - C++: undefined behavior

Performance Characteristics

AspectRustGoJavaC++
Thread overheadSystem threads or M:NM:N (goroutines)System or virtualSystem threads
Context switchOS-level or cooperativeCheap (goroutines)OS-levelOS-level
MemoryPredictable (no GC)GC pausesGC pausesPredictable
Async overheadZero-cost futuresRuntime overheadBoxing overheadDepends

When to Use What

ScenarioBest Choice
CPU-bound parallelismRust (rayon), C++
I/O-bound concurrencyRust (tokio), Go, Node.js
Low latency requiredRust, C++
Rapid developmentGo, Python
Complex concurrent stateRust (compile-time safety)

Mental Model Shifts

From Go

Before: "Just use goroutines and channels"
After:  "Explicitly declare what can be shared and how"

Key shifts:

  • Arc<Mutex<T>> instead of implicit sharing
  • Compiler enforces thread safety
  • Async needs explicit runtime

From Java

Before: "synchronized everywhere, hope for the best"
After:  "Types encode thread safety, compiler enforces"

Key shifts:

  • No need for synchronized keyword
  • Mutex contains data, not separate
  • No GC pauses in critical sections

From C++

Before: "Be careful, read the docs, use sanitizers"
After:  "Compiler catches data races, trust the type system"

Key shifts:

  • Send/Sync replace convention
  • RAII locks are mandatory, not optional
  • Much harder to write incorrect concurrent code

你可能感兴趣的文章

Concurrency

  • 所属分类: AI
  • 本文标签: rust
  • 版权声明: 本文链接 https://seaxiang.com/blog/ZJQ44ZJq