Concorrenza ruggine

Concorrenza ruggine
La concorrenza si riferisce a una funzione che consente a parti autonome di un programma di eseguire parallele ad altre sezioni del codice. La concorrenza consente a diverse parti di un programma di eseguire contemporaneamente, migliorando le prestazioni.

Passiamo attraverso i boschi della programmazione di concorrenza nel linguaggio di programmazione della ruggine. Tieni presente che questo articolo non è progettato per essere una guida completa alla programmazione di concorrenza. Funge solo da base per espandere e creare applicazioni più complesse.

Processi e thread

Quando scriviamo un normale programma ed eseguiamolo su un sistema di destinazione, il sistema operativo host esegue il codice in un processo. Un processo si riferisce a un'unità di un eseguibile specificato.

Tuttavia, nei moderni sistemi e applicazioni, si dispone di parti dello stesso codice eseguite contemporaneamente utilizzando thread.

Nella maggior parte dei casi, sentirai spesso il termine multi-threading usato dove si verifica la concorrenza. Questo perché stiamo essenzialmente generando più thread e permettendo loro di correre paralleli tra loro.

Prendiamo un programma di base per illustrare come funziona un normale programma e come utilizzare la concorrenza per migliorarlo.

Prendi in considerazione un programma con due loop come mostrato:

Usa std :: thread;
Usa std :: time :: durata;
fn main ()
Per I in 0… = 5
println!("", io);
// Dormi per 1000 ms
Discussione :: sleep (durata :: from_millis (1000));

Per I in 0… = 5
println!("", io);
Discussione :: sleep (durata :: from_millis (1000));

Nel codice di esempio sopra, abbiamo due loop che iterano da 0 a 5. Tuttavia, in ogni iterazione, dormiamo per 1000 millisecondi.

Il metodo thread :: sleep ci consente di mettere un thread specifico per dormire per la durata specificata.

Se si esegue il codice sopra, si noti che il primo loop attende che il secondo ciclo sia completato prima che possa iniziare a funzionare.

Questo perché entrambi i loop sono su un singolo thread.

Se vogliamo che entrambi i loop siano eseguiti contemporaneamente, dobbiamo metterli in diversi thread.

Rust Crea filo

Possiamo creare nuovi thread usando il modulo thread. Fa parte della libreria standard e ci fornisce una serie di strumenti e funzioni per lavorare con i thread.

Possiamo importarlo usando l'istruzione:

Usa std :: thread;

Abbiamo anche bisogno del modulo di durata dal thread del tempo. Possiamo importarlo come:

Usa std :: time :: durata

Per creare un nuovo thread in ruggine, utilizzare il metodo thread :: spawn. Questo metodo prende una chiusura come argomento.

La chiusura, in questo caso, definisce il codice da eseguire all'interno del thread.

La sintassi è come mostrato di seguito:

Discussione :: Spawn (|| chiusura)

Perfezioniamo il codice precedente e mettiamo ogni costrutto in un thread separato. Il codice di esempio è come mostrato:

Usa std :: thread;
Usa std :: time :: durata;
fn main ()
// Crea nuovo thread
std :: thread :: spawn (muove ||
Per I in 0… = 5
println!("", io);
Discussione :: sleep (durata :: from_millis (1000));

);
Per I in 0… = 5
println!("", io);
Discussione :: sleep (durata :: from_millis (1000));

Nel programma di esempio sopra, creiamo un nuovo thread usando la funzione thread :: spawn e passiamo il primo ciclo come chiusura.

Nel thread principale, eseguiamo il secondo ciclo. Ciò consente a entrambi i loop di funzionare contemporaneamente. Il codice sopra dovrebbe restituire l'output come:

0
0
1
1
2
2
3
3
4
4
5
5

Cosa succede se il thread principale esce prima che il thread "interno"? Un esempio è come mostrato di seguito:

Usa std :: thread;
Usa std :: time :: durata;
fn main ()
// thread interiore
std :: thread :: spawn (muove ||
Per I in 0… = 5
println!("", io);
Discussione :: sleep (durata :: from_millis (1000));

);
// principale
Per I in 0… = 5
println!("", io);
Discussione :: sleep (durata :: from_millis (2));

In questo esempio, il thread principale richiede meno tempo per dormire e quindi completerà più velocemente prima che il thread interno completa.

In tal caso, il thread interno verrà eseguito solo mentre il thread principale è in esecuzione. Il codice sopra restituirà l'output incompleto come:

0
0
1
2
3
4
5

Questo perché il thread "interno" viene terminato prima del completamento.

Rust Juncia maniglie

Abbiamo visto come si comporta un thread se il thread principale esce prima del completamento. Possiamo unirci alle due maniglie per risolvere un tale caso e lasciare che l'altro thread attenda un altro.

Le maniglie di unire consentiranno al thread principale di attendere gli altri thread prima della chiusura.

Per unire le maniglie, utilizziamo il metodo di join come mostrato nella sintassi seguente:

let handle_name = thread :: spawn (chiusure);
Handle_name.giuntura().scartare();

Ridefiniamo il nostro esempio di loop, in cui il thread principale esce presto.

Usa std :: thread;
Usa std :: time :: durata;
fn main ()
let handle = std :: thread :: spawn (muove ||
Per I in 0… = 5
println!("", io);
Discussione :: sleep (durata :: from_millis (1000));

);
Per I in 0… = 5
println!("", io);
Discussione :: sleep (durata :: from_millis (2));

// handle join
maniglia.giuntura().scartare();

Nel codice di esempio sopra, creiamo una variabile Handle che contiene il thread. Inseriamo quindi il thread usando il metodo join ().

Il metodo di downrap ci consente di gestire gli errori.

Poiché il thread principale dorme per un tempo più breve, dovrebbe essere completato prima del thread "interno". Tuttavia, dovrebbe attendere che l'altro thread esca a causa del metodo di join.

L'output è come mostrato:

0
0
1
2
3
4
5
1
2
3
4
5

Si noti che il thread principale emette tutti i valori a breve durata e attende che l'altro thread sia completato.

Filo ruggine muovi la chiusura

Potresti aver notato la parola chiave sposta all'interno della chiusura del thread nel nostro esempio precedente. La chiusura di spostamento viene utilizzata con il metodo thread :: spawn per consentire la condivisione dei dati tra i thread.

Usando la parola chiave sposta, possiamo consentire a un thread di trasferire la proprietà dei valori a un altro thread.

Prendi un programma di esempio di seguito:

Usa std :: thread;
Usa std :: time :: durata;
fn main ()
Siar = [1,2,3,4,5];
let handle = std :: thread :: spawn (||
per me in arr.iter ()
println!("", io);
Discussione :: sleep (durata :: from_millis (100));

);
maniglia.giuntura().scartare();

Nel codice sopra, dichiariamo un array chiamato ARR nel thread principale. Quindi generare un nuovo thread senza la chiusura.

Nota: poiché stiamo cercando di accedere all'array ARR e renderlo parte dell'ambiente di chiusura, la compilazione fallirà in quanto non è disponibile in quel thread.

Possiamo usare la parola chiave mossa per forzare la chiusura nel thread per assumere la proprietà dell'array.

Possiamo correggere il codice sopra aggiungendo la chiusura di spostamento come mostrato:

Usa std :: thread;
Usa std :: time :: durata;
fn main ()
Siar = [1,2,3,4,5];
let handle = std :: thread :: spawn (muove ||
per me in arr.iter ()
println!("", io);
Discussione :: sleep (durata :: from_millis (100));

);
maniglia.giuntura().scartare();

Ciò consente al thread di assumere la proprietà dell'array e iterarlo. Questo dovrebbe tornare:

1
2
3
4
5

Conclusione

Quelli erano i fondamenti della programmazione simultanea nel linguaggio di programmazione della ruggine. Sebbene questo articolo funga da base concreta per la concorrenza della ruggine, non copre concetti avanzati. È possibile controllare la documentazione per i dettagli.