Comment la multitâche préemptive est-elle implémentée en Ruby?
sobes.tech IA
Réponse de l'IA
Dans Ruby "pur" (MRI, JRuby, TruffleRuby), il n’existe pas de véritable multitâche préemptive pour l’exécution parallèle du code dans un seul processus en raison du Global Interpreter Lock (GIL). Le GIL permet à un seul thread d’exécuter du code Ruby à la fois.
Cependant, la multitâche préemptive en Ruby existe au niveau de l’entrée/sortie. Lorsqu’un thread effectue une opération d’entrée/sortie bloquante (par exemple, lire un fichier, faire une requête réseau), le GIL est libéré, permettant à un autre thread d’exécuter du code Ruby. Cela permet d’atteindre un parallélisme pour les opérations d’entrée/sortie, mais pas pour les tâches CPU-bound.
Il existe des implémentations alternatives de Ruby (par exemple, Rubinius) qui ont tenté d’implémenter une véritable multitâche sans GIL, mais elles n’ont pas connu une diffusion aussi large que MRI.
Pour l’exécution parallèle des tâches CPU-bound en Ruby, on utilise généralement:
- Processus (
fork) : Chaque processus a son propre GIL, ce qui permet d’exécuter du code Ruby en parallèle. La communication entre processus nécessite des mécanismes explicites (IPC). - Bibliothèques externes et extensions en C : Les opérations implémentées en C peuvent s’exécuter en dehors du contrôle du GIL, assurant une exécution parallèle.
Dans Ruby 3.0, le Planificateur de Fibers a été introduit, permettant d’effectuer de manière asynchrone des opérations d’entrée/sortie en utilisant des fibers et des appels non bloquants. Cela améliore la performance pour les tâches I/O-bound, mais ne rend pas les tâches CPU-bound réellement parallèles dans un seul processus.
# Exemple d’utilisation de threads en MRI pour une tâche I/O-bound
require 'net/http'
require 'uri'
urls = %w[http://example.com http://ruby-lang.org]
threads = urls.map do |url|
Thread.new do
uri = URI.parse(url)
response = Net::HTTP.get_response(uri)
puts "Téléchargé #{url} (Statut: #{response.code})"
end
end
threads.each(&:join)
Ainsi, bien que Ruby dispose de moyens pour travailler avec des threads, la véritable multitâche préemptive pour les tâches liées au CPU est généralement atteinte par l’utilisation de plusieurs processus ou par des implémentations spécifiques de Ruby sans GIL.