Sobes.tech
Middle+

Kā Ruby realizē priekšlaicīgu daudzuzdevumu?

sobes.tech AI

Atbilde no AI

"Tīrs" Ruby (MRI, JRuby, TruffleRuby) nav paties īstas izstumjošas daudzuzdevumu izpildes veids vienā procesā, jo Global Interpreter Lock (GIL) neļauj vairākām pavedieniem vienlaikus izpildīt Ruby kodu. GIL ļauj izpildīt tikai vienam pavedienam Ruby kodu jebkurā laikā:

Tomēr, izstumjošā daudzuzdevumu izpilde Ruby ir pieejama ievades-izvades līmenī. Kad pavediens veic bloķējošu ievades-izvades operāciju (piemēram, faila lasīšanu, tīkla pieprasījumu), GIL tiek atbrīvots, ļaujot citam pavedienam izpildīt Ruby kodu. Tas ļauj sasniegt paralēlismu ievades-izvades operācijām, bet ne CPU-bound uzdevumiem:

Ir pieejamas alternatīvas Ruby realizācijas (piemēram, Rubinius), kas mēģināja īstenot patiesu izstumjošu daudzuzdevumu bez GIL, bet tās nav guvušas tik plašu izplatību kā MRI:

Par CPU-bound uzdevumu paralēlu izpildi Ruby parasti izmanto:

  • Procesus (fork) — katram procesam ir savs GIL, kas ļauj paralēli izpildīt Ruby kodu. Datu apmaiņa starp procesiem prasa īpašus mehānismus (IPC).
  • Ārējas bibliotēkas un C paplašinājumus — C valodā realizētas operācijas var tikt izpildītas ārpus GIL kontroles, nodrošinot paralēlu izpildi:

Ruby 3.0 ieviesa Fibers Scheduler, kas ļauj asinhroni izpildīt ievades-izvades operācijas, izmantojot fibres un neblokējošus izsaukumus. Tas uzlabo veiktspēju I/O-bound uzdevumiem, bet nepadara CPU-bound uzdevumus patiesi paralēlus vienā procesā:

# Piemērs ar MRI pavedieniem I/O-bound uzdevumiem
require 'net/http'
require 'uri'

urls = %w[http://example.com http://ruby-lang.org]
threds = urls.map do |url|
  Thread.new do
    uri = URI.parse(url)
    response = Net::HTTP.get_response(uri)
    puts "Lejupielādēts #{url} (Statuss: #{response.code})"
  end
end

threads.each(&:join)

Tādējādi, lai gan Ruby ir rīki pavedienu darbībai, patiesa izstumjoša daudzuzdevumu izpilde CPU-bound uzdevumiem galvenokārt tiek sasniegta, izmantojot vairākus procesus vai īpašas Ruby realizācijas bez GIL.