Rust Basics - Concurrency
Rust Basics - Concurrency
Rust makes concurrent programming safe and fearless. The ownership and type systems prevent data races at compile time.
Threads
Creating threads with std::thread:
use std::thread;
use std::time::Duration;fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("Hi from spawned thread {}", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("Hi from main thread {}", i);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap();
}
Moving Data to Threads
use std::thread;fn main() {
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", v);
});
handle.join().unwrap();
}
Message Passing with Channels
use std::sync::mpsc;
use std::thread;fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
});
let received = rx.recv().unwrap();
println!("Got: {}", received);
}
Multiple Producers
let (tx, rx) = mpsc::channel();let tx1 = tx.clone();
thread::spawn(move || {
tx1.send("from thread 1").unwrap();
});
thread::spawn(move || {
tx.send("from thread 2").unwrap();
});
for received in rx {
println!("Got: {}", received);
}
Shared State with Mutex
use std::sync::{Arc, Mutex};
use std::thread;fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
Send and Sync Traits
Send: Type can be transferred between threadsSync: Type can be shared between threads (&TisSend)
Async/Await
use std::future::Future;async fn do_something() {
println!("doing something");
}
async fn async_main() {
let future = do_something();
future.await;
}
fn main() {
// Using tokio runtime
// tokio::runtime::Runtime::new().unwrap().block_on(async_main());
}
Concurrent Async
use tokio::time::{sleep, Duration};async fn task1() {
sleep(Duration::from_secs(1)).await;
println!("Task 1 done");
}
async fn task2() {
sleep(Duration::from_secs(1)).await;
println!("Task 2 done");
}
async fn main_async() {
// Run concurrently
tokio::join!(task1(), task2());
}
Choosing Your Approach
| Use Case | Recommendation |
|----------|---------------|
| CPU-bound work | thread::spawn |
| I/O-bound work | async/await with tokio |
| Message passing | mpsc::channel |
| Shared mutable state | Arc |
| Read-heavy shared data | Arc |
Rust's type system ensures thread safety without runtime overhead!