Wątki
Wykonywanie współbieżne
Wątki to bezpłatna lekcja Ruby Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Ruby Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Ruby Academy zawiera 4 lekcji w sumie.
Czym jest wątek?
Wątek to niezależna ścieżka wykonywania wewnątrz programu. Ruby pozwala uruchamiać kilka wątków, dzięki czemu ich praca może nakładać się w czasie.
- Główny program działa w wątku głównym.
- Więcej wątków tworzy się za pomocą
Thread.new. - Wątki współdzielą tę samą pamięć, więc mogą odczytywać i zapisywać te same zmienne.
Wątki świetnie sprawdzają się, gdy program spędza czas na oczekiwaniu (na sieć, dysk lub upływ czasu), ponieważ jeden wątek może czekać, podczas gdy inny nadal pracuje.
Tworzenie wątku
Przekaż blok do Thread.new. Blok zostanie wykonany w nowym wątku. Wywołaj join, aby zaczekać na jego zakończenie przed zakończeniem programu.
t = Thread.new do
puts "Hello from the new thread"
end
t.join
puts "Main thread done"Dlaczego join ma znaczenie
Gdy wątek główny się kończy, Ruby kończy działanie i może nie czekać na pozostałe wątki. join blokuje wywołującego do momentu zakończenia wskazanego wątku.
Bez join wątek roboczy może nie zdążyć nic wypisać, zanim program się zakończy.
t = Thread.new do
sleep 0.1
puts "Worker finished"
end
puts "Waiting..."
t.join
puts "All done"Wiele wątków jednocześnie
Można uruchomić grupę wątków, zebrać je w tablicy, a następnie wywołać join dla każdego z nich. To częsty wzorzec w przypadku pracy wejścia-wyjścia, która może być wykonywana w przybliżeniu równolegle.
threads = (1..3).map do |n|
Thread.new do
puts "Thread number " + n.to_s
end
end
threads.each(&:join)
puts "Finished all threads"Współdzielenie zmiennych
Wątki współdzielą pamięć. Zmienna zdefiniowana przed utworzeniem wątku jest widoczna wewnątrz niego. To potężna funkcja, ale również źródło problemów, jeśli dwa wątki zapisują tę samą wartość.
counter = 0
t = Thread.new do
counter += 1
end
t.join
puts "Counter is " + counter.to_sWarunki wyścigu
Warunek wyścigu występuje, gdy wątki przeplatają aktualizacje współdzielonych danych, a wynik zależy od czasu ich wykonania.
counter += 1w rzeczywistości oznacza odczyt, zwiększenie i zapis.- Dwa wątki mogą odczytać tę samą starą wartość i oba zapisać tę samą nową wartość, przez co jedno zwiększenie zostanie utracone.
Rozwiązaniem jest skoordynowanie dostępu za pomocą blokady.
Mutex: blokada
Mutex (wzajemne wykluczanie) gwarantuje, że w danej chwili tylko jeden wątek wykonuje chroniony kod. Owiń sekcję krytyczną w mutex.synchronize.
mutex = Mutex.new
counter = 0
threads = (1..5).map do
Thread.new do
mutex.synchronize do
counter += 1
end
end
end
threads.each(&:join)
puts "Counter is " + counter.to_sZwracanie wartości
Thread#value czeka na zakończenie wątku i zwraca wartość jego bloku — działa jak automatyczne połączenie join z pobraniem wyniku.
t = Thread.new do
2 + 3
end
puts "Result is " + t.value.to_sZmienne lokalne dla wątku
Każdy wątek może przechowywać własne wartości pod kluczami będącymi symbolami za pomocą Thread.current[:key]. Wartości te są prywatne dla danego wątku i nigdy nie są współdzielone.
t = Thread.new do
Thread.current[:name] = "worker"
puts "Inside: " + Thread.current[:name]
end
t.joinObsługa wyjątków
Jeśli wątek zgłosi błąd, pozostanie on niezauważony do chwili wywołania join lub value, które zgłoszą go ponownie. Ustawienie Thread.abort_on_exception = true sprawia, że błędy natychmiast kończą cały program, co ułatwia debugowanie.
t = Thread.new do
raise "boom"
end
begin
t.join
rescue => e
puts "Caught: " + e.message
endKiedy wątki pomagają
Wątki świetnie sprawdzają się w pracy typu I/O-bound, w której czas jest spędzany na oczekiwaniu. Są mniej pomocne w pracy typu CPU-bound ze względu na GVL, które zostanie omówione w następnej części.
- Dobre zastosowania: pobieranie wielu adresów URL, odczytywanie wielu plików.
- Ograniczone zastosowania: intensywne obliczenia numeryczne rozłożone na wiele rdzeni.
Współdzielony, modyfikowalny stan należy zawsze chronić za pomocą Mutex.
Szybki test
Sprawdź swoją wiedzę na temat wątków.
Podsumowanie: wątki
Najważniejsze informacje o wątkach Ruby:
Thread.newrozpoczyna współbieżne wykonywanie.joinczeka, avalueczeka i zwraca wynik.- Wątki współdzielą pamięć, co prowadzi do warunków wyścigu.
Mutexwraz zsynchronizechroni współdzielony stan.- Wątki świetnie nadają się do pracy typu I/O-bound.
Następnie wyjaśnimy, dlaczego wątki nie mogą w pełni wykorzystywać wielu rdzeni procesora: chodzi o GVL.
Często zadawane pytania
Czy lekcja „Wątki” jest bezpłatna?
Tak — pełny tekst „Wątki” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Ruby Academy, przejdź na CoddyKit PRO. Kurs Ruby Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Wątki”?
Wykonywanie współbieżne Ćwiczysz Ruby Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Ruby Academy?
Nie wymagamy żadnego doświadczenia. Ruby Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Wątki”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Ruby Academy?
Tak. Każda lekcja Ruby Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.