00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Concorrenza in Rust

Rust offre fearless concurrency: il compilatore garantisce l’assenza di data race a compile-time grazie al sistema di ownership e ai trait Send e Sync.

Concorrenza vs Parallelismo

  • Concorrenza: più task fanno progressi in modo alternato
  • Parallelismo: più task vengono eseguiti simultaneamente su core diversi

Rust supporta entrambi i modelli.

Trait Send e Sync

  • Send: un tipo può essere trasferito tra thread (quasi tutti i tipi)
  • Sync: un tipo può essere condiviso tra thread tramite riferimenti
// Rc<T> NON è Send né Sync (non thread-safe)
// Arc<T> è sia Send che Sync (thread-safe)
// RefCell<T> è Send ma NON Sync
// Mutex<T> è sia Send che Sync

Thread

use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        println!("Ciao dal thread!");
    });

    handle.join().unwrap(); // Attende il completamento
}

Stato Condiviso con Arc + Mutex

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let contatore = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let contatore = Arc::clone(&contatore);
        let handle = thread::spawn(move || {
            let mut num = contatore.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Risultato: {}", *contatore.lock().unwrap()); // 10
}

Canali (Message Passing)

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        tx.send("Ciao dal thread!").unwrap();
    });

    let messaggio = rx.recv().unwrap();
    println!("{}", messaggio);
}

Scoped Threads

Thread con scope che possono prendere in prestito dati dal thread principale:

fn main() {
    let mut dati = vec![1, 2, 3];

    thread::scope(|s| {
        s.spawn(|| {
            println!("Dati: {:?}", dati); // Borrow immutabile OK
        });
    });

    dati.push(4); // Dopo lo scope, l'ownership torna al main
}

Approcci alla Concorrenza

Approccio Quando usarlo
Thread + Mutex Stato condiviso tra pochi thread
Canali (mpsc) Comunicazione produttore-consumatore
Async/Await I/O-bound con molti task concorrenti
Rayon (crate) Parallelismo sui dati (map-reduce)
// Esempio con rayon per parallelismo sui dati
use rayon::prelude::*;

let somma: i32 = (0..1_000_000)
    .into_par_iter()
    .map(|x| x * 2)
    .sum();

Conclusione

Rust è unico nel garantire la sicurezza della concorrenza a compile-time. Il compilatore impedisce data race, use-after-free e accessi non sincronizzati. Scegli tra thread con stato condiviso, message passing con canali o async/await in base alle esigenze del tuo programma. La garanzia di “fearless concurrency” rende Rust ideale per software multi-threaded ad alte performance.