Rdzewieć współbieżność

Rdzewieć współbieżność
Współbieżność odnosi się do funkcji, która pozwala samodzielnym częściom programu działać równolegle do innych sekcji kodu. Współbieżność pozwala jednocześnie działać różnym częściom programu, co poprawia wydajność.

Spacerujmy po lesie programowania współbieżności w języku programowania rdzy. Należy pamiętać, że jest to artykuł nie został zaprojektowany jako kompletny przewodnik po programowaniu współbieżności. Służy jedynie jako podstawa do rozszerzania i tworzenia bardziej złożonych aplikacji.

Procesy i wątki

Kiedy piszemy normalny program i wykonujemy go w systemie docelowym, system operacyjny hosta wykonuje kod w procesie. Proces odnosi się do jednostki określonego wykonywalnego.

Jednak w nowoczesnych systemach i aplikacjach masz części tego samego kodu uruchomionego jednocześnie za pomocą wątków.

W większości przypadków często usłyszysz termin zastosowany wielokresta. Dzieje się tak, ponieważ zasadniczo odradzamy wiele wątków i pozwalamy im działać równolegle do siebie.

Weźmy podstawowy program, aby zilustrować, jak działa normalny program i jak wykorzystywać współbieżność, aby go ulepszyć.

Rozważ program z dwiema pętlami, jak pokazano:

Użyj std :: wątek;
Użyj std :: czas :: czas trwania;
fn main ()
Dla i w 0… = 5
println!("", I);
// śpij przez 1000 ms
wątek :: Sleep (czas :: from_millis (1000));

Dla i w 0… = 5
println!("", I);
wątek :: Sleep (czas :: from_millis (1000));

W powyższym przykładowym kodzie mamy dwie pętle, które iterują od 0 do 5. Jednak w każdej iteracji śpimy przez 1000 milisekund.

Metoda wątku :: Sleep pozwala nam uśpić określony wątek na określony czas trwania.

Jeśli uruchomisz powyższy kod, zauważysz, że pierwsza pętla czeka na zakończenie drugiej pętli, zanim zacznie się uruchomić.

Dzieje się tak, ponieważ obie pętle znajdują się w jednym wątku.

Jeśli chcemy, aby obie pętle działały jednocześnie, musimy umieścić je w różnych wątkach.

Rust Utwórz wątek

Możemy tworzyć nowe wątki za pomocą modułu wątku. Jest częścią standardowej biblioteki i zapewnia nam pakiet narzędzi i funkcji do pracy z wątkami.

Możemy go zaimportować za pomocą instrukcji:

Użyj std :: wątek;

Potrzebujemy również modułu czasu trwania z wątku czasu. Możemy to zaimportować jako:

Użyj std :: czas :: czas trwania

Aby utworzyć nowy wątek w rdzy, użyj metody wątku ::. Ta metoda zamyka się jako argument.

Zamknięcie w tym przypadku definiuje kod do uruchomienia wewnątrz wątku.

Składnia jest jak pokazana poniżej:

Wątek :: Spawn (|| zamknięcie)

Udoskonalmy poprzedni kod i umieść każdy konstrukt w osobnym wątku. Przykładowy kod jest tak, jak pokazano:

Użyj std :: wątek;
Użyj std :: czas :: czas trwania;
fn main ()
// Utwórz nowy wątek
STD :: Thread :: spawn (ruch ||
Dla i w 0… = 5
println!("", I);
wątek :: Sleep (czas :: from_millis (1000));

);
Dla i w 0… = 5
println!("", I);
wątek :: Sleep (czas :: from_millis (1000));

W powyższym przykładowym programie tworzymy nowy wątek za pomocą funkcji wątku :: Spawn i przekazujemy pierwszą pętlę jako zamknięcie.

W głównym wątku uruchamiamy drugą pętlę. To pozwala obie pętle działać jednocześnie. Kod powyżej powinien zwrócić dane wyjściowe jako:

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

Co się stanie, jeśli główny wątek wyjdzie przed zakończeniem wątku „wewnętrznego”? Przykładem jest to, jak pokazano poniżej:

Użyj std :: wątek;
Użyj std :: czas :: czas trwania;
fn main ()
// Wewnętrzny wątek
STD :: Thread :: spawn (ruch ||
Dla i w 0… = 5
println!("", I);
wątek :: Sleep (czas :: from_millis (1000));

);
// główny
Dla i w 0… = 5
println!("", I);
wątek :: Sleep (czas trwania :: from_millis (2));

W tym przykładzie główny wątek wymaga mniej czasu na sen, a zatem ukończy się szybciej przed zakończeniem wewnętrznego wątku.

W takim przypadku wewnętrzny wątek będzie działał tylko podczas działania głównego wątku. Powyższy kod zwróci niekompletne dane wyjściowe jako:

0
0
1
2
3
4
5

Wynika to z faktu, że wątek „wewnętrzny” jest zakończony przed zakończeniem.

Uchwyty łączające rdzę

Widzieliśmy, jak wątek zachowuje się, jeśli główny wątek kończy się przed jego zakończeniem. Możemy dołączyć do dwóch uchwytów, aby rozwiązać taką sprawę i pozwolić, aby drugi wątek czekał na inny.

Połączenie uchwytów pozwoli głównej wątkowi czekać na inne wątki przed zakończeniem.

Aby dołączyć do uchwytów, używamy metody połączenia, jak pokazano w poniższej składni:

LET HANDED_NAME = WHERNE :: Spawn (Closure);
Nazwa_wytła.dołączyć().odwijać się();

Na nowo zdefiniujmy nasz przykład pętli, w którym główny wątek kończy się wcześnie.

Użyj std :: wątek;
Użyj std :: czas :: czas trwania;
fn main ()
Let uchwyt = std :: wątek :: spawn (ruch ||
Dla i w 0… = 5
println!("", I);
wątek :: Sleep (czas :: from_millis (1000));

);
Dla i w 0… = 5
println!("", I);
wątek :: Sleep (czas trwania :: from_millis (2));

// Dołącz uchwyt
uchwyt.dołączyć().odwijać się();

W powyższym przykładowym kodzie tworzymy zmienną uchwytu, która utrzymuje wątek. Następnie dołączamy do wątku za pomocą metody łączenia ().

Metoda rozpakowania pozwala nam obsługiwać błędy.

Ponieważ główny wątek śpi przez krótszy czas, należy go ukończyć przed wątkiem „wewnętrznym”. Powinien jednak poczekać, aż drugi wątek wyjdzie z powodu metody połączenia.

Wyjście jest tak, jak pokazano:

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

Należy zauważyć, że główny wątek wysyła wszystkie wartości w krótkim czasie i czeka na zakończenie drugiego wątku.

Zamknięcie ruchu nić rdzy

Być może zauważyłeś słowo kluczowe przenoszenia wewnątrz zamknięcia wątku w naszym poprzednim przykładzie. Zamknięcie ruchu jest używane z metodą wątku :: Spawn, aby umożliwić udostępnianie danych między wątkami.

Korzystając z słowa kluczowego ruchu, możemy pozwolić wątkowi przenieść własność wartości do innego wątku.

Weźmy przykład programu poniżej:

Użyj std :: wątek;
Użyj std :: czas :: czas trwania;
fn main ()
Niech ARR = [1,2,3,4,5];
Pozwól uchwycić = std :: wątpt :: spawn (||
bo w ARR.iter ()
println!("", I);
wątek :: Sleep (czas :: from_millis (100));

);
uchwyt.dołączyć().odwijać się();

W powyższym kodzie deklarujemy tablicę o nazwie ARR w głównym wątku. Następnie odradzamy nowy wątek bez zamknięcia ruchu.

Uwaga: Ponieważ staramy się uzyskać dostęp do tablicy ARR i uczynić ją częścią środowiska zamknięcia, kompilacja zawiedzie, ponieważ nie jest dostępna w tym wątku.

Możemy użyć słowa kluczowego ruchu, aby wymusić zamknięcie wątku, aby przejąć własność tablicy.

Możemy naprawić powyższy kod, dodając zamknięcie ruchu, jak pokazano:

Użyj std :: wątek;
Użyj std :: czas :: czas trwania;
fn main ()
Niech ARR = [1,2,3,4,5];
Let uchwyt = std :: wątek :: spawn (ruch ||
bo w ARR.iter ()
println!("", I);
wątek :: Sleep (czas :: from_millis (100));

);
uchwyt.dołączyć().odwijać się();

To pozwala wątkowi przejąć własność tablicy i ją iterować. To powinno powrócić:

1
2
3
4
5

Wniosek

To były podstawy jednoczesnego programowania w języku programowania rdzy. Chociaż ten artykuł służy jako konkretna podstawa współbieżności rdzy, nie obejmuje zaawansowanych koncepcji. Szczegółowe informacje możesz sprawdzić dokumentację.