Sobes.tech
Middle+

Ako je v Ruby implementovaný predbežný multitasking?

sobes.tech AI

Odpoveď od AI

V "čistom" Ruby (MRI, JRuby, TruffleRuby) ne existuje skutočná predbežná multitasking pre paralelné vykonávanie kódu v jednom procese kvôli Global Interpreter Lock (GIL). GIL umožňuje, že iba jedno vlákno vykonáva Ruby kód v danom momente.

Avšak, predbežná multitasking v Ruby existuje na úrovni vstupu/výstupu. Keď vlákno vykonáva blokujúcu operáciu vstupu/výstupu (napríklad čítanie súboru, sieťová požiadavka), GIL sa uvoľní, čo umožňuje inému vláknu vykonávať Ruby kód. To umožňuje dosiahnuť paralelizmus pre operácie vstupu/výstupu, ale nie pre CPU-bound úlohy.

Existujú alternatívne implementácie Ruby (napríklad Rubinius), ktoré sa pokúsili implementovať skutočnú multitaskingu bez GIL, ale nedosiahli takú širokú rozšírenosť ako MRI.

Pre paralelné vykonávanie CPU-bound úloh v Ruby sa zvyčajne používajú:

  • Procesy (fork): Každý proces má svoj vlastný GIL, čo umožňuje paralelné vykonávanie Ruby kódu. Výmena dát medzi procesmi vyžaduje explicitné mechanizmy (IPC).
  • Externé knižnice a rozšírenia v C: Operácie implementované v C môžu byť vykonávané mimo kontroly GIL, zabezpečujúc paralelné vykonávanie.

V Ruby 3.0 bol zavedený Fibers Scheduler, ktorý umožňuje asynchrónne vykonávanie operácií vstupu/výstupu pomocou fiberov a neblokujúcich volaní. To zlepšuje výkon pre I/O-bound úlohy, ale nečiní CPU-bound úlohy skutočne paralelnými v jednom procese.

# Príklad použitia vlákien v MRI pre I/O-bound úlohy
require 'net/http'
require 'uri'

urls = %w[http://example.com http://ruby-lang.org]
vlákna = urls.map do |url|
  Thread.new do
    uri = URI.parse(url)
    response = Net::HTTP.get_response(uri)
    puts "Stiahnuté #{url} (Stav: #{response.code})"
  end
end

vlákna.each(&:join)

Teda, hoci Ruby má mechanizmy na prácu s vláknami, skutočná predbežná multitasking pre CPU-závislé úlohy sa zvyčajne dosahuje použitím viacerých procesov alebo špecifických Ruby implementácií bez GIL.