یکی از ویژگیهای برجستهی Rust، توانایی ساخت برنامههای همزمان و چندنخی ایمن است؛ بدون نگرانی از مشکلاتی مانند race condition یا deadlock (در صورت رعایت قوانین borrow checker). در این بخش با ابزارها و تکنیکهای همزمانی در Rust آشنا میشویم.
Rust از طریق استاندارد لایبرری، امکان ایجاد و مدیریت threadها را به سادگی فراهم میکند.
ایجاد یک thread:
use std::thread;fn main() {let handle = thread::spawn(|| {println!("سلام از نخ دیگر!");});println!("سلام از نخ اصلی!");handle.join().unwrap(); // منتظر پایان نخ جدید میمانیم}
- thread::spawn یک نخ جدید ایجاد میکند.
- join() منتظر میماند تا نخ کامل شود.
برای اشتراک دادهها بین نخها و تغییر ایمن آنها:
Arc (Atomic Reference Counted):
برای اشتراکگذاری داده بین چند نخ:
use std::sync::Arc;
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!("نتیجه: {}", *counter.lock().unwrap());}
برای ارتباط بین نخها، Rust از channelها استفاده میکند:
use std::sync::mpsc;use std::thread;fn main() {let (tx, rx) = mpsc::channel();thread::spawn(move || {tx.send("پیام از نخ دیگر").unwrap();});let received = rx.recv().unwrap();println!("دریافت شد: {}", received);}
Rust از نسخه ۲۰۱۸ به بعد پشتیبانی بومی از async/await دارد که نوشتن کدهای همزمان را ساده میکند.
async fn say_hello() {println!("سلام async");}#[tokio::main]async fn main() {say_hello().await;}
- async fn تابعی بازمیگرداند که Future است.
- برای اجرای آن باید از runtime مانند Tokio استفاده کرد.
Tokio محبوبترین runtime برای اجرای کدهای async است و ابزارهایی مانند timer، stream، channel async و موارد دیگر فراهم میکند.
مثال ساده:
#[tokio::main]async fn main() {let handle = tokio::spawn(async {println!("این در نخ async اجرا میشود");});handle.await.unwrap();}
Tokio همراه با کتابخانههای دیگر مثل async-std, hyper, و reqwest اکوسیستم قدرتمندی برای برنامههای async فراهم میکند.
در این بخش یاد گرفتیم:
- چگونه با threadهای استاندارد نخهای جدید بسازیم.
- چطور با Arc و Mutex دادهها را بین نخها به اشتراک بگذاریم و به صورت ایمن تغییر دهیم.
- استفاده از channelها برای ارتباط نخها.
- و چگونه با async/await و Tokio برنامههای همزمان مدرن بنویسیم.