Storicamente il GIL di Ruby impediva l'esecuzione parallela di thread. Ruby 3 ha introdotto i Ractor, che eseguono codice davvero in parallelo isolando lo stato.
lavoratori = 4.times.map do |i|
Ractor.new(i) do |n|
# calcolo pesante, in parallelo su piu' core
(1..1_000_000).sum { |x| x * n }
end
end
risultati = lavoratori.map(&:take) # raccogli gli esiti
La regola d'oro: i Ractor non condividono stato mutabile. Comunicano solo passando messaggi (send/take), e gli oggetti condivisi devono essere immutabili (freeze). Questo elimina alla radice le race condition.
È un modello alla "actor" (come Erlang): isolamento invece di lock. In cambio dell'assenza di stato condiviso, ottieni parallelismo reale per lavori CPU-bound.
Ancora sperimentale in alcuni aspetti, ma è la direzione di Ruby per sfruttare i core moderni senza il caos dei thread condivisi.