Async & Concurrency
Async — suspend → async/.await
The shape is similar to coroutines, but Rust doesn’t ship a runtime — you add one (almost always tokio).
Kotlin — coroutines
suspend fun fetch(): String { ... }
val data = fetch()Rust — async/await
async fn fetch() -> String { ... }
let data = fetch().await; // postfix .await#[tokio::main] // sets up the executor, like a coroutine scope
async fn main() {
let (a, b) = tokio::join!(fetch_a(), fetch_b()); // ~ awaitAll / coroutineScope
}Key differences from coroutines:
async fnreturns aFuturethat is lazy — it does nothing until.awaited or spawned (Kotlin coroutines are eager once launched).- No built-in
Dispatchers/ structured concurrency — the runtime (tokio) providesspawn,join!,select!, channels. .awaitis postfix (x.await) and chains cleanly.
Concurrency & the Send/Sync guarantee
Kotlin relies on you to avoid data races. Rust makes them a compile error via the same ownership rules plus two marker traits:
Send— safe to move to another thread.Sync— safe to share (&T) across threads.
use std::thread;
use std::sync::{Arc, Mutex};
let counter = Arc::new(Mutex::new(0)); // shared, thread-safe ownership
let mut handles = vec![];
for _ in 0..10 {
let c = Arc::clone(&counter);
handles.push(thread::spawn(move || { // `move` transfers ownership into the thread
*c.lock().unwrap() += 1;
}));
}
for h in handles { h.join().unwrap(); }The famous slogan “fearless concurrency”: if it compiles, it has no data races. That’s the payoff for the borrow checker.
Last updated on