Sobes.tech
Middle+

Jak w Ruby realizowana jest przerywana wielozadaniowość?

sobes.tech AI

Odpowiedź od AI

W "czystym" Ruby (MRI, JRuby, TruffleRuby) nie ma prawdziwego preemptive multitaskingu do równoległego wykonywania kodu w jednym procesie z powodu Global Interpreter Lock (GIL). GIL pozwala tylko jednemu wątkowi na wykonywanie kodu Ruby w danym momencie.

Jednakże, preemptive multitasking w Ruby występuje na poziomie wejścia/wyjścia. Gdy wątek wykonuje blokującą operację wejścia/wyjścia (np. odczyt pliku, zapytanie sieciowe), GIL jest zwalniany, co pozwala innemu wątkowi na wykonywanie kodu Ruby. To umożliwia osiągnięcie równoległości dla operacji wejścia/wyjścia, ale nie dla zadań CPU-bound.

Istnieją alternatywne implementacje Ruby (np. Rubinius), które próbowały zaimplementować prawdziwą wielozadaniowość bez GIL, ale nie zdobyły tak szerokiego rozpowszechnienia jak MRI.

Do równoległego wykonywania zadań CPU-bound w Ruby zwykle używa się:

  • Procesów (fork): Każdy proces ma własny GIL, co pozwala na równoległe wykonywanie kodu Ruby. Wymiana danych między procesami wymaga jawnych mechanizmów (IPC).
  • Zewnętrznych bibliotek i rozszerzeń C: Operacje zaimplementowane w C mogą być wykonywane poza kontrolą GIL, zapewniając równoległe wykonanie.

W Ruby 3.0 wprowadzono Planer Fibers, który pozwala na asynchroniczne wykonywanie operacji wejścia/wyjścia, korzystając z fiberów i wywołań nieblokujących. To poprawia wydajność dla zadań I/O-bound, ale nie czyni zadań CPU-bound prawdziwie równoległymi w jednym procesie.

# Przykład użycia wątków w MRI dla zadań I/O-bound
require 'net/http'
require 'uri'

urls = %w[http://example.com http://ruby-lang.org]
wątki = urls.map do |url|
  Thread.new do
    uri = URI.parse(url)
    response = Net::HTTP.get_response(uri)
    puts "Pobrano #{url} (Status: #{response.code})"
  end
end

wątki.each(&:join)

Podsumowując, choć Ruby ma mechanizmy do pracy z wątkami, prawdziwy preemptive multitasking dla zadań związanych z CPU jest zwykle osiągany poprzez użycie wielu procesów lub specyficznych implementacji Ruby bez GIL.