Pourquoi le même calcul peut être 100× plus rapide
Exemple conducteur du cours : l’estimation de \(\pi\) par Monte-Carlo (séquentiel → multi-thread → GPU).
Julia comme banc d’essai, Python comme point de comparaison.
▶ Notebook (démo + corrigé) : Interprété vs compilé
numpy vs boucle Julia.@code_lowered → @code_typed → @code_native.Distinction clé — quand le type est-il connu ? À l’exécution (Python) : redécouvert à chaque opération → lent. À la compilation (Julia/JIT) : connu une fois, code spécialisé → rapide.
@code_warntype (le rouge = Any).@btime / @benchmark.obj.methode()).▶ Notebook (démo + corrigé) : Multiple dispatch vs POO Python
aire(Cercle) / aire(Rectangle))interaction(a, b) selon le couple de types.a.methode(b).* bascule sur GPU parce que ses arguments sont des CuArray.▶ Notebook (démo + corrigé) : Threads & concurrence
threading ne parallélise pas le CPU (un seul thread exécute du bytecode).@threads tourne vraiment sur plusieurs cœurs.s += xs[i] partagé → résultat faux et non déterministe.Warning
En mémoire partagée, écrire au même endroit depuis plusieurs threads sans précaution = corruption silencieuse. Pas d’erreur, juste un résultat faux.
| Approche | Correct ? | Rapide ? |
|---|---|---|
s += ... partagé |
❌ | — |
@atomic partout |
✅ | ❌ |
| accumulateurs locaux + réduction | ✅ | ✅ |
Paralléliser une réduction, ce n’est pas « ajouter
@threads» : c’est minimiser le partage.
▶ Notebook (démo + corrigé) : Mémoire & GPU
La performance ne vient pas d’un langage magique, mais de comprendre ce que la machine fait vraiment : le coût de chaque opération, qui partage quoi, et où voyagent les données.
En filigrane de tout le cours : type découvert à l’exécution = lent ; type connu à la compilation = rapide.
Comment travailler