0Pricing
Ruby Academy · Lekcja

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_s

Warunki wyścigu

Warunek wyścigu występuje, gdy wątki przeplatają aktualizacje współdzielonych danych, a wynik zależy od czasu ich wykonania.

  • counter += 1 w 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_s

Zwracanie 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_s

Zmienne 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.join

Obsł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
end

Kiedy 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.new rozpoczyna współbieżne wykonywanie.
  • join czeka, a value czeka i zwraca wynik.
  • Wątki współdzielą pamięć, co prowadzi do warunków wyścigu.
  • Mutex wraz z synchronize chroni 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.

Wszystkie lekcje w tym kursie

  1. Wątki
  2. Wyjaśnienie GVL
  3. Fibers
  4. Ractors
← Powrót do Ruby Academy