Comprendi l'approccio di Rust alla concorrenza basato sul concetto di "concorrenza senza paura".
La concorrenza è la capacità di un programma di eseguire più attività contemporaneamente sullo stesso core della CPU. Le attività simultanee vengono eseguite e completate in tempi sovrapposti senza un ordine specificato, a differenza del parallelismo, dove varie attività o attività secondarie della stessa attività vengono eseguite contemporaneamente su hardware con più processori.
Rust si distingue per le sue caratteristiche prestazionali e il supporto per la concorrenza in modo sicuro ed efficiente. L'approccio di Rust alla concorrenza si basa sul concetto di "concorrenza senza paura" in cui il linguaggio mira a rendere facile la scrittura sicura codice concorrente attraverso il suo sistema di proprietà e prestito che applica regole rigide in fase di compilazione per impedire tracce di dati e garantire la memoria sicurezza.
Comprensione della concorrenza in Rust
Rust fornisce diverse primitive di concorrenza per la scrittura di programmi concorrenti, inclusi thread, passaggio di messaggi, mutex, tipi atomici e async/await per la programmazione asincrona.
Ecco una panoramica delle primitive di concorrenza di Rust:
- Discussioni: La ruggine fornisce a std:: filo modulo nella sua libreria standard per la creazione e la gestione dei thread. Puoi generare nuovi thread con il file filo:: spawn funzione. IL filo:: spawn accetta una chiusura contenente il codice per l'esecuzione. Puoi anche eseguire thread che possono essere eseguiti in parallelo e Rust fornisce primitive di sincronizzazione per coordinare la loro esecuzione. Il controllore del prestito assicura che i riferimenti non portino a comportamenti imprevisti.
- Passaggio di messaggi: il modello di concorrenza di Rust supporta il passaggio di messaggi tra i thread. Utilizzerai i canali implementati tramite il std:: sync:: mpsc modulo per il passaggio di messaggi. Un canale è costituito da un trasmettitore (Mittente) e un ricevitore (Ricevitore). I thread possono inviare messaggi tramite il trasmettitore e riceverli tramite il ricevitore. Ciò fornisce un modo sicuro e sincronizzato di comunicare tra i thread.
- Mutex e tipi atomici: Rust fornisce le primitive di sincronizzazione, inclusi i mutex (std:: sync:: Mutex) e tipi atomici (std:: sync:: atomico), per garantire l'accesso esclusivo alla condivisione dei dati. I mutex consentono a più thread di accedere ai dati contemporaneamente, evitando corse di dati. I tipi atomici forniscono operazioni atomiche su dati condivisi, ad esempio l'incremento di un contatore, senza richiedere un blocco esplicito.
- Async/Await e Futures: Ruggine asincrono/attendere la sintassi fornisce funzionalità per la scrittura di codice asincrono che è possibile eseguire contemporaneamente. I programmi asincroni gestiscono in modo efficiente le attività legate all'I/O consentendo ai programmi di eseguire altre attività mentre attendono altre operazioni di I/O. Di ruggine asincrono/attendere la sintassi si basa sui futures e puoi alimentarli con il async-std O tokio librerie di esecuzione.
I thread Rust sono leggeri e l'assenza di sovraccarico di runtime li rende adatti per applicazioni ad alte prestazioni. Le primitive di concorrenza di Rust si integrano perfettamente con più librerie e framework per diverse esigenze di concorrenza.
Come utilizzare i thread di spawn in Rust
Userai il std:: filo modulo per generare thread. IL std:: thread:: spawn La funzione ti consente di creare un nuovo thread che verrà eseguito contemporaneamente al thread principale o a qualsiasi altro thread esistente nel tuo programma.
Ecco come puoi generare un thread con il file std:: thread:: spawn funzione:
utilizzo std:: filo;
fnprincipale() {
// Crea un nuovo thread
permettere thread_handle = thread:: spawn(|| {
// Il codice eseguito nel nuovo thread va qui
stampa!("Ciao dal nuovo thread!");
});// Attendi che il thread generato finisca
thread_handle.join().unwrap();
// Il codice eseguito nel thread principale continua qui
stampa!("Ciao dal thread principale!");
}
IL principale La funzione crea un nuovo thread con il file filo:: spawn funzione passando una chiusura contenente il codice per l'esecuzione nel thread (in questo caso la chiusura è una funzione anonima). La chiusura stampa un messaggio che indica che il nuovo thread è in esecuzione.
IL giuntura metodo sul thread_handle consente al thread principale di attendere il completamento dell'esecuzione del thread generato. A chiamata giuntura, la funzione garantisce che il thread principale attenda il completamento del thread generato prima di procedere.
Puoi generare più thread e utilizzare un loop o qualsiasi altro Struttura antiruggine per creare più chiusure e spawn thread per ciascuna.
utilizzo std:: filo;
fnprincipale() {
permettere num_thread = 5;permetteremut thread_handles = vec![];
per io In0..num_thread {
permettere thread_handle = thread:: spawn(mossa || {
stampa!("Ciao dal thread {}", io);
});
thread_handles.push (thread_handle);
}per maniglia In thread_handles {
handle.join().unwrap();
}
stampa!("Tutti i thread sono finiti!");
}
Il ciclo for genera cinque thread, ciascuno assegnato a un identificatore univoco io con la variabile ciclo. Le chiusure catturano il valore di io con il mossa parola chiave da evitare problemi di proprietà, e il thread_handles vector memorizza i thread per dopo nel file giuntura ciclo continuo.
Dopo aver generato tutti i thread, il file principale la funzione itera sul thread_handles vettore, chiamate giuntura su ciascun handle e attende l'esecuzione di tutti i thread.
Passaggio di messaggi attraverso i canali
Puoi passare i messaggi attraverso i thread con i canali. Rust fornisce funzionalità per il passaggio di messaggi nel file std:: sync:: mpsc modulo. Qui, mpsc sta per "multiple producer, single consumer" e consente la comunicazione tra più thread inviando e ricevendo messaggi attraverso i canali.
Ecco come implementare il messaggio che passa attraverso i canali di comunicazione inter-thread nei tuoi programmi:
utilizzo std:: sync:: mpsc;
utilizzo std:: filo;fnprincipale() {
// Crea un canale
permettere (mittente, destinatario) = mpsc:: canale();// Genera un thread
discussione:: spawn(mossa || {
// Invia un messaggio attraverso il canale
mittente.send("Ciao dal thread!").scartare();
});
// Riceve il messaggio nel thread principale
permettere messaggio_ricevuto = ricevitore.recv().unwrap();
stampa!("Messaggio ricevuto: {}", messaggio_ricevuto);
}
IL principale funzione crea un canale con mpsc:: canale() che restituisce a mittente e un ricevitore. IL mittente invia messaggi al ricevitore che riceve i messaggi. IL principale la funzione procede a generare thread e spostare la proprietà del file Mittente alla chiusura del filo. All'interno della chiusura del filo, il mittente.send() La funzione invia un messaggio attraverso il canale.
IL ricevitore.recv() La funzione riceve il messaggio interrompendo l'esecuzione finché il thread non ha ricevuto il messaggio. IL principale La funzione stampa il messaggio sulla console dopo che il messaggio è stato ricevuto con successo.
Si noti che l'invio di un messaggio attraverso il canale consuma il mittente. Se devi inviare messaggi da più thread, puoi clonare il mittente con l'estensione mittente.clone() funzione.
Inoltre, il mpsc modulo fornisce altri metodi come try_recv(), che non bloccante tenta di ricevere un messaggio, e iter(), che crea un iteratore sui messaggi ricevuti.
Il passaggio dei messaggi attraverso i canali fornisce un modo sicuro e conveniente per comunicare tra i thread, evitando corse di dati e garantendo una sincronizzazione adeguata.
Il modello di proprietà e prestito di Rust garantisce la sicurezza della memoria
Rust combina la proprietà, il prestito e il controllo del prestito per fornire un framework di programmazione concorrente robusto, sicuro.
Il controllo del prestito funge da rete di sicurezza, rilevando potenziali problemi in fase di compilazione anziché fare affidamento su controlli di runtime o Garbage Collection.