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.