0Pricing
Ruby Academy · Leçon

Threads

Exécution concurrente

Threads est une leçon Ruby Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Ruby Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Ruby Academy comprend 4 leçons au total.

Qu’est-ce qu’un fil d’exécution ?

Un fil d’exécution est un chemin d’exécution indépendant au sein de votre programme. Ruby vous permet d’exécuter plusieurs fils d’exécution afin que les tâches puissent se chevaucher dans le temps.

  • Le programme principal s’exécute dans le fil d’exécution principal.
  • Vous créez d’autres fils d’exécution avec Thread.new.
  • Les fils d’exécution partagent la même mémoire : ils peuvent donc lire et modifier les mêmes variables.

Les fils d’exécution sont particulièrement adaptés lorsque votre programme passe du temps à attendre (le réseau, le disque ou une pause), car un fil peut attendre pendant qu’un autre continue à travailler.

Créer un fil d’exécution

Passez un bloc à Thread.new. Le bloc s’exécute dans un nouveau fil d’exécution. Appelez join pour attendre sa fin avant que le programme ne se termine.

t = Thread.new do
  puts "Hello from the new thread"
end

t.join
puts "Main thread done"

Pourquoi <code>join</code> est important

Lorsque le fil d’exécution principal se termine, Ruby quitte le programme et peut ne pas attendre les autres fils d’exécution. join bloque l’appelant jusqu’à ce que le fil d’exécution cible soit terminé.

Sans join, le fil de travail risque de ne jamais avoir l’occasion d’afficher son résultat avant l’arrêt du programme.

t = Thread.new do
  sleep 0.1
  puts "Worker finished"
end

puts "Waiting..."
t.join
puts "All done"

Plusieurs fils d’exécution à la fois

Vous pouvez lancer un groupe de fils d’exécution, les rassembler dans un tableau, puis appeler join pour chacun d’eux. C’est un schéma courant pour les tâches d’entrée-sortie quasi parallèles.

threads = (1..3).map do |n|
  Thread.new do
    puts "Thread number " + n.to_s
  end
end

threads.each(&:join)
puts "Finished all threads"

Partager des variables

Les fils d’exécution partagent la mémoire. Une variable définie avant le fil est visible à l’intérieur de celui-ci. C’est puissant, mais aussi dangereux si deux fils d’exécution écrivent la même valeur.

counter = 0

t = Thread.new do
  counter += 1
end

t.join
puts "Counter is " + counter.to_s

Conditions de concurrence

Une condition de concurrence se produit lorsque des fils d’exécution entrelacent leurs mises à jour de données partagées et que le résultat dépend du moment où elles ont lieu.

  • counter += 1 correspond en réalité à une lecture, une addition, puis une écriture.
  • Deux fils d’exécution peuvent lire la même ancienne valeur et écrire tous les deux la même nouvelle valeur, ce qui fait perdre une incrémentation.

La solution consiste à coordonner l’accès à l’aide d’un verrou.

Exclusion mutuelle : un verrou

Un Mutex (exclusion mutuelle) garantit qu’un seul fil d’exécution à la fois exécute le code protégé. Encadrez la section critique avec mutex.synchronize.

mutex = Mutex.new
counter = 0

threads = (1..5).map do
  Thread.new do
    mutex.synchronize do
      counter += 1
    end
  end
end

threads.each(&:join)
puts "Counter is " + counter.to_s

Renvoyer une valeur

Thread#value attend la fin du fil d’exécution et renvoie la valeur de son bloc, comme si vous appeliez automatiquement join tout en obtenant un résultat.

t = Thread.new do
  2 + 3
end

puts "Result is " + t.value.to_s

Variables locales aux fils d’exécution

Chaque fil d’exécution peut stocker ses propres valeurs, indexées par un symbole, avec Thread.current[:key]. Ces valeurs sont privées à ce fil et ne sont jamais partagées.

t = Thread.new do
  Thread.current[:name] = "worker"
  puts "Inside: " + Thread.current[:name]
end

t.join

Gérer les exceptions

Si un fil d’exécution déclenche une erreur, celle-ci reste silencieuse jusqu’à ce que vous appeliez join ou value, ce qui la déclenche à nouveau. Définir Thread.abort_on_exception = true fait immédiatement échouer tout le programme en cas d’erreur, ce qui facilite le débogage.

t = Thread.new do
  raise "boom"
end

begin
  t.join
rescue => e
  puts "Caught: " + e.message
end

Quand les fils d’exécution sont utiles

Les fils d’exécution sont très efficaces pour les tâches limitées par les E/S, lorsque le temps est principalement consacré à l’attente. Ils sont moins utiles pour les tâches limitées par le CPU en raison du GVL, que nous étudierons ensuite.

  • Adapté : télécharger de nombreuses URL et lire de nombreux fichiers.
  • Limité : effectuer des calculs numériques intensifs sur plusieurs cœurs.

Protégez toujours l’état mutable partagé avec un Mutex.

Vérification rapide

Testez votre compréhension des fils d’exécution.

Récapitulatif : fils d’exécution

Vous avez appris les notions essentielles sur les fils d’exécution Ruby :

  • Thread.new démarre une exécution concurrente.
  • join attend ; value attend et renvoie un résultat.
  • Les fils d’exécution partagent la mémoire, ce qui peut provoquer des conditions de concurrence.
  • Un Mutex avec synchronize protège l’état partagé.
  • Les fils d’exécution sont particulièrement performants pour les tâches limitées par les E/S.

Nous allons ensuite voir pourquoi les fils d’exécution ne peuvent pas exploiter pleinement plusieurs cœurs du CPU : le GVL.

Questions Fréquemment Posées

La leçon « Threads » est-elle gratuite ?

Oui — le texte complet de « Threads » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Ruby Academy, passe à CoddyKit PRO. Le cours Ruby Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Threads » ?

Exécution concurrente Tu pratiques Ruby Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Ruby Academy ?

Aucune expérience préalable n'est requise. Ruby Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « Threads » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Ruby Academy ?

Oui. Chaque leçon Ruby Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Threads
  2. Le GVL expliqué
  3. Fibres
  4. Ractors
← Retour à Ruby Academy