Threads
Threads in TypeScript vs Rust
Section titled “Threads in TypeScript vs Rust”In Node.js or the browser, you cannot run arbitrary JavaScript in parallel on another CPU core. You can spawn a Web Worker, but it runs in a completely separate process: you cannot share a closure or pass a reference — only serializable data can cross the boundary via postMessage.
Rust gives you real OS threads via std::thread::spawn. These threads run in the same process, share the same memory address space, and can receive values (not serialized copies) from the parent thread — as long as the ownership rules are satisfied.
std::thread::spawn
Section titled “std::thread::spawn”thread::spawn takes a closure and runs it on a new OS thread. The closure must move any data it needs from the surrounding scope, because the thread might outlive the current stack frame.
The call returns a JoinHandle<T> where T is the return type of the closure. Calling .join() on the handle blocks until the thread finishes and returns Result<T, Box<dyn Any>>.
// TypeScript (Node.js): no real threads// Web Workers run in a separate process// and communicate only via postMessage (serialized data)import { Worker, isMainThread, parentPort, workerData } from 'worker_threads';
if (isMainThread) { const worker = new Worker(__filename, { workerData: { value: 10 } }); worker.on('message', (result) => console.log('result:', result));} else { // In worker — cannot share closures or references from main thread parentPort?.postMessage(workerData.value * 2);}use std::thread;
fn main() { let value = 10u32; // owned by main thread
// move closure takes ownership of 'value' let handle = thread::spawn(move || { // 'value' is now owned by this thread value * 2 });
// join() blocks until the thread completes // and returns the closure's return value let result = handle.join().unwrap(); println!("result: {result}"); // result: 20}Spawning multiple threads and collecting results
Section titled “Spawning multiple threads and collecting results”A common pattern is to spawn a fixed number of worker threads, collect all JoinHandles into a Vec, then join them all and aggregate the results.
// TypeScript: parallel work via Promise.allasync function sumChunks(data: number[][]): Promise<number> { const partials = await Promise.all( data.map(chunk => new Promise<number>(resolve => resolve(chunk.reduce((a, b) => a + b, 0)) ) ) ); return partials.reduce((a, b) => a + b, 0);}use std::thread;
fn main() { let chunks: Vec<Vec<u32>> = vec![ vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9], ];
let handles: Vec<_> = chunks .into_iter() .map(|chunk| { thread::spawn(move || chunk.iter().sum::<u32>()) }) .collect();
let total: u32 = handles .into_iter() .map(|h| h.join().unwrap()) .sum();
println!("total: {total}"); // total: 45}Try it
Section titled “Try it”use std::thread;
fn main() { let chunks: Vec<Vec<u32>> = vec![ vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9], ];
let handles: Vec<_> = chunks .into_iter() .map(|chunk| { thread::spawn(move || chunk.iter().sum::<u32>()) }) .collect();
let total: u32 = handles .into_iter() .map(|h| h.join().unwrap()) .sum();
println!("total: {total}");}Compiling…