Aller au contenu

Exercices#

Calculer des factorielles en parallèle#

  • Introduction à la définition du calcul factorial, n! = n*(n-1)*(n-2)*...*3*2*1. Ceci sera notre cas d'étude pour l'introduction à la concurrence.

Implémentation séquentielle du calcul de factoriels#

  • Écrire une fonction séquentielle simple en Go pour calculer les factoriels. Utilisez une boucle for pour cela.
    func Factorial(n uint64) uint64 {
      if n < 2 {
          return 1
      }
      var fact uint64 = 1
      for i := 2; i <= int(n); i++ {
          fact *= uint64(i)
      }
      return fact
    }
    

Conversion de l'implémentation en version concurrente avec goroutines et canaux#

  • Introduire les goroutines avec go func(). Ce sont des fonctions qui peuvent s'exécuter en parallèle avec d'autres goroutines.
  • Présentation des canaux pour la communication entre les goroutines. On utilise chan pour la déclaration.
  • Modification de la fonction Factorial pour utiliser les goroutines et les canaux. Le calcul de chaque terme de la multiplication est maintenant une goroutine.
    func ConcurrentFactorial(n uint64) uint64 {
      if n < 2 {
          return 1
      }
      facts := make(chan uint64, n)
      for i := 2; i <= int(n); i++ {
          go func(j int) {
              facts <- uint64(j)
          }(i)
      }
      var fact uint64 = 1
      for i := 2; i <= int(n); i++ {
          fact *= <-facts
      }
      return fact
    }
    

Analyse des performances et optimisation#

  • Introduction de la bibliothèque time pour mesurer le temps d'exécution des fonctions.
  • Comparaison de la performance de l'implémentation séquentielle avec celle de l'implémentation concurrente.
  • Discussion sur le coût de création des goroutines et sur la manière d'optimiser le code pour de meilleures performances.

Développer un système de files d'attente (queue) pour traiter des tâches en parallèle#

Conception d'un système de files d'attente#

  • Présentation de la structure Queue et de ses méthodes : Enqueue, Dequeue, IsEmpty.
  • Exemple de code :
    type Queue []Task
    
    func (q *Queue) Enqueue(t Task) {
      *q = append(*q, t)
    }
    
    func (q *Queue) Dequeue() (Task, bool) {
      if len(*q) == 0 {
          return Task{}, false
      }
      t := (*q)[0]
      *q = (*q)[1:]
      return t, true
    }
    
    func (q *Queue) IsEmpty() bool {
      return len(*q) == 0
    }
    

Implémentation du système de files d'attente avec goroutines et canaux#

  • Modification de la structure Queue pour utiliser des goroutines et des canaux.
  • Discussion sur la synchronisation des goroutines avec sync.WaitGroup.
  • Présentation des mécanismes de verrouillage avec sync.Mutex pour éviter les conditions