Sobes.tech
Middle+

Como é implementada a multitarefa preemptiva em Ruby?

sobes.tech IA

Resposta da IA

No Ruby "puro" (MRI, JRuby, TruffleRuby), não existe uma multitarefa preemptiva verdadeira para execução paralela de código num único processo devido ao Global Interpreter Lock (GIL). O GIL permite que apenas um thread execute código Ruby de cada vez.

No entanto, a multitarefa preemptiva em Ruby existe ao nível de entrada/saída. Quando um thread realiza uma operação de entrada/saída bloqueante (por exemplo, ler um arquivo, fazer uma requisição de rede), o GIL é liberado, permitindo que outro thread execute código Ruby. Isto permite alcançar paralelismo para operações de entrada/saída, mas não para tarefas CPU-bound.

Existem implementações alternativas de Ruby (por exemplo, Rubinius) que tentaram implementar uma verdadeira multitarefa sem GIL, mas elas não tiveram tanta difusão quanto o MRI.

Para execução paralela de tarefas CPU-bound em Ruby, geralmente usam-se:

  • Processos (fork): Cada processo tem seu próprio GIL, permitindo executar código Ruby em paralelo. A troca de dados entre processos requer mecanismos explícitos (IPC).
  • Bibliotecas externas e extensões em C: Operações implementadas em C podem ser executadas fora do controlo do GIL, garantindo execução paralela.

No Ruby 3.0 foi introduzido o Programador de Fibers, que permite realizar operações de entrada/saída de forma assíncrona usando fibers e chamadas não bloqueantes. Isto melhora o desempenho para tarefas I/O-bound, mas não torna as tarefas CPU-bound verdadeiramente paralelas num único processo.

# Exemplo de uso de threads em MRI para tarefas I/O-bound
require 'net/http'
require 'uri'

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

hilos.each(&:join)

Portanto, embora o Ruby tenha mecanismos para trabalhar com threads, a verdadeira multitarefa preemptiva para tarefas relacionadas com CPU é geralmente alcançada através do uso de múltiplos processos ou implementações específicas de Ruby sem GIL.