Concurrency Overview
Concurrency in TypeScript vs Rust
Section titled “Concurrency in TypeScript vs Rust”JavaScript runs on a single thread. The event loop processes one task at a time and delegates I/O to the operating system. Concurrency in JS is cooperative: your code yields control by hitting an await, and the event loop picks up the next queued callback. Nothing truly runs in parallel inside your JS process unless you spin up a Web Worker — a separate process that communicates only via postMessage.
Rust takes a radically different approach. You get real OS threads out of the box, a first-class async/await system that works on top of a user-space runtime (Tokio is the standard choice), and a compiler that statically prevents data races at compile time. Rust calls this fearless concurrency — you can write concurrent code and the compiler will refuse to compile programs that have data-race bugs.
Two concurrency models in Rust
Section titled “Two concurrency models in Rust”| Model | Rust primitive | JS analogy |
|---|---|---|
| OS threads (parallel CPU work) | std::thread::spawn | Web Workers (limited) |
| Async I/O (many concurrent tasks, one thread pool) | async/await + Tokio | Promise / async/await |
| Shared mutable state (threads) | Arc<Mutex<T>> | SharedArrayBuffer + Atomics |
| Message passing (threads) | std::sync::mpsc | worker.postMessage |
Why “fearless”?
Section titled “Why “fearless”?”The Rust ownership and type system enforces two rules at compile time:
- A value can have many readers or one writer — never both simultaneously.
- Data shared across threads must implement the
SendandSyncmarker traits, which the compiler verifies automatically.
If you try to share a raw &mut T across threads, the program will not compile. No runtime lock, no silent corruption — the bug is caught before your code runs.
// JavaScript: single-threaded, concurrency via event loopasync function fetchAll(urls: string[]): Promise<string[]> { // All fetches start "in parallel" (concurrent I/O) // but JS code itself runs on one thread return Promise.all(urls.map(url => fetch(url).then(r => r.text())));}
// Web Worker for CPU-bound parallelism (separate process)const worker = new Worker('./worker.js');worker.postMessage({ data: [1, 2, 3] });worker.onmessage = (e) => console.log(e.data);use std::thread;
fn main() { // Real OS thread — runs truly in parallel on another CPU core let h1 = thread::spawn(|| "fearless"); let h2 = thread::spawn(|| "concurrency");
// join() waits for the thread and returns its result let r1 = h1.join().unwrap(); let r2 = h2.join().unwrap(); println!("{r1} {r2}"); // fearless concurrency}Try it
Section titled “Try it”use std::thread;
fn main() { let h1 = thread::spawn(|| "fearless"); let h2 = thread::spawn(|| "concurrency"); let r1 = h1.join().unwrap(); let r2 = h2.join().unwrap(); println!("{r1} {r2}");}Compiling…