Vous lancez 100 000 parties d’un jeu de dés dans Excel avec une table de données et le Gestionnaire des tâches plafonne à ~15 % de CPU. Voici pourquoi cela arrive et comment accélérer réellement vos simulations Monte‑Carlo.
Pourquoi Excel exploite si peu de CPU en Monte‑Carlo
Vue d’ensemble de la question
Scénario typique : un classeur lance 100 000 itérations via Analyse de scénarios > Table de données. Le PC dispose d’un CPU 13ᵉ génération avec de nombreux cœurs, mais Excel n’en utilise visiblement qu’un seul ; la mémoire reste à l’aise (~40 %). L’utilisateur s’interroge : le moteur de calcul est‑il monothread ? L’option « Calcul multithread » sert‑elle vraiment ? Quelles solutions pour accélérer ou répartir la charge ?
Réponse & solutions en un coup d’œil
Point clé | Explication | Pistes d’optimisation |
---|---|---|
Moteur principalement monothread | La chaîne de dépendances d’une feuille est évaluée dans un ordre strict pour garantir des résultats cohérents. Si les formules d’une zone dépendent l’une de l’autre (cas d’une table de données ou de fonctions volatiles comme RANDBETWEEN/RAND ), le calcul s’exécute inévitablement sur un seul cœur. | — |
Calcul multithread limité | Excel parallélise : (1) des blocs de cellules indépendants, (2) certains algorithmes matriciels (MMULT , MDETERM …), (3) des fonctions marquées « thread‑safe ». La table de données, Recherche d’objectif et Solver restent, pour des raisons historiques, exécutés sur un seul thread. | Concevoir le modèle en blocs indépendants (plages/feuilles isolées) permet à Excel d’allouer un thread par bloc. |
Fonctions volatiles | Chaque appel de RANDBETWEEN force un recalcul complet : 100 000 × 75 cellules ⇒ ~7,5 M de tirages. | (1) Générer tous les tirages une fois puis figer en valeurs (Collage spécial). (2) Produire la série via un add‑in ou Python/R et la coller dans Excel. |
Table de données séquentielle | Implémentée selon l’héritage Lotus 1‑2‑3 : la boucle interne n’a jamais été repensée pour le parallélisme et rejoue le classeur paramètre par paramètre. | Remplacer les tables de données par : formules matricielles dynamiques (LET + MAP/BYROW/REDUCE ), Power Query pour simuler hors feuille, ou Python in Excel pour appeler numpy.random . |
Mémoire sous‑utilisée | Une simulation représentant quelques millions de cellules occupe peu face à 16–64 Go ; le goulet est le thread de calcul, pas la RAM. | — |
Ce que fait réellement le moteur de calcul
À chaque recalcul, Excel construit un graphe de dépendances et exécute les nœuds dans un ordre garantissant qu’une cellule est toujours calculée après ses antécédents. Quand le classeur contient des îlots indépendants, Excel peut assigner un thread par îlot ; c’est l’option « Calcul multithread ». En revanche, une table de données procède ainsi :
- Pour chaque ligne/colonne de la table, Excel remplace les paramètres d’entrée.
- Il recalcule les cellules dépendantes nécessaires pour produire les sorties.
- Il écrit le résultat dans la cellule de la table, puis passe au scénario suivant.
Ce déroulé est séquentiel. Ajoutez des fonctions volatiles (RAND, RANDBETWEEN, OFFSET, INDIRECT, TODAY, NOW, CELL…) : le moindre changement déclenche un nouveau passage sur la chaîne entière. Le multithreading ne peut donc pas s’exprimer : un seul thread fait (et refait) le travail.
Pourquoi la table de données reste un goulot
- Compatibilité : la table de données existe depuis les premières versions d’Excel. Sa sémantique (rejouer le modèle scénario par scénario) est garantie pour des millions de fichiers dans le monde. Une exécution parallèle modifierait des détails subtils (ordre d’évaluation, événements, temporisations) et risquerait de casser des classeurs.
- Volatilité : avec des aléas, chaque scénario exige de recalculer la chaîne complète pour obtenir un nouveau tirage, ce qui supprime l’intérêt de la mise en cache.
- Granularité : une table de données alimente souvent une cellule de sortie unique (gain/perte). L’overhead de gestion de fil (thread) serait plus coûteux que le bénéfice de paralleliser des calculs minuscules.
Stratégies concrètes pour accélérer
Remplacer la table de données par des formules matricielles dynamiques
Avec Microsoft 365, les formules dynamiques permettent de générer N essais en une seule formule, souvent bien plus rapide et plus « thread‑friendly » que les tables de données. Exemple : simulation de deux dés, somme et histogramme.
Hypothèses : B1
contient le nombre d’itérations N
. Formule :
=LET(
n; $B$1;
tirages; RANDARRAY(n; 2; 1; 6; VRAI);
sommes; BYROW(tirages; LAMBDA(r; SUM(r)));
k; SEQUENCE(11; ; 2); /* valeurs 2..12 */
freq; MAP(k; LAMBDA(x; COUNTIF(sommes; x))); /* histogramme */
HSTACK(k; freq) /* 2 colonnes */
)
Avantages : un seul bloc calcule tout (facile à isoler), pas de boucle « scénario par scénario », et possibilité pour Excel d’optimiser la matrice en interne. Une fois satisfait, figez les tirages : copiez la plage, puis Collage spécial > Valeurs pour stabiliser le jeu de données.
Réduire la volatilité : générer une fois, réutiliser
Chaque cellule RANDBETWEEN
est volatile. Remplacez des milliers d’appels par RANDARRAY
(une seule formule) ; ou, mieux encore, générez une fois et figez. Deux approches :
- Étapes manuelles : insérez une matrice de tirages (
RANDARRAY
), copiez‑collez en valeurs, puis consommez ces tirages avec des fonctions non volatiles. - Approche hybride : générez la série aléatoire dans Python/R (voir plus bas) et collez le résultat dans une feuille « Données ».
Basculer la boucle dans VBA (et écrire en bloc)
VBA reste monothread, mais vous évitez les recalculs de feuille et la couche de dépendances. Le gain tient à trois principes : (1) désactiver mise à jour et calcul automatique, (2) travailler en mémoire (tableaux VBA), (3) écrire en une fois vers la feuille.
' Module VBA : Monte-Carlo 2 dés
Sub SimulerDesVBA()
Dim N As Long: N = Range("B1").Value ' nombre d'itérations
Dim i As Long
Dim R() As Long: ReDim R(1 To N, 1 To 1) ' résultats en mémoire
```
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Randomize
For i = 1 To N
' deux tirages 1..6
R(i, 1) = 1 + Int(6 * Rnd) + 1 + Int(6 * Rnd)
Next i
With Range("D2").Resize(N, 1) ' écriture en bloc
.Value = R
End With
```
Sortie:
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Sur des volumes > 100 000 itérations, cette approche est souvent 10× à 50× plus rapide qu’une table de données, car vous contournez le moteur de dépendances. Ensuite, calculez les agrégats (moyenne, histogrammes) avec des formules classiques.
Paralléliser « à l’ancienne » avec plusieurs instances d’Excel
Excel ne parallélise pas une table de données, mais rien n’empêche de lancer plusieurs instances d’Excel (processus séparés) et de répartir le travail :
- Démarrez 3–8 instances Excel (selon vos cœurs).
- Ouvrez des classeurs indépendants (sans lien entre eux).
- Attribuez à chacun une fraction des itérations (p. ex. 8 classeurs × 12500 = 100 000).
- Écrivez les résultats dans des CSV distincts, puis consolidez dans un classeur final.
Attention : évitez que plusieurs processus écrivent en même temps dans le même fichier XLSX (risque de corruption). Préférez des sorties temporaires (CSV/Parquet) puis une consolidation.
Utiliser Python in Excel (ou Python/R/Julia hors Excel)
Les bibliothèques vectorisées (NumPy, pandas) exploitent mieux le cache CPU et peuvent paralléliser certaines opérations. Exemple avec Python in Excel :
=PY("
import numpy as np, pandas as pd
n = int(B1)
r = np.random.randint(1, 7, size=(n, 2))
s = r.sum(axis=1)
k = np.arange(2, 13)
c = np.array([(s == val).sum() for val in k])
result = pd.DataFrame({'Somme': k, 'Comptage': c})
return result
")
Python exécute la génération de nombres et la réduction côté moteur Python, puis renvoie un tableau directement exploitable dans Excel. Vous pouvez ensuite figer ces valeurs et poursuivre l’analyse avec vos formules habituelles.
Power Query pour « pré‑calculer »
Power Query (Obtenir et transformer) n’est pas pensé pour le temps réel mais il convient pour générer des jeux de données aléatoires en amont et les rafraîchir à la demande. L’intérêt : vous gardez vos feuilles non volatiles et contrôlez le moment du recalcul (Rafraîchir).
Recoder des UDF thread‑safe (XLL/.NET)
Si votre modèle repose sur des fonctions personnalisées (UDF), un add‑in en C/C++ ou .NET peut marquer certaines fonctions thread‑safe, autorisant Excel à les paralléliser. Pour un Monte‑Carlo lourd, une UDF vectorisée (entrée/sortie matricielle) peut remplacer des milliers d’appels scalaires et améliorer drastiquement le débit.
Options Excel à vérifier
- Fichier > Options > Formules :
- Activer Calcul multithread et Utiliser tous les processeurs. Utile pour des blocs indépendants, sans effet sur les tables de données.
- Basculer en Calcul manuel et déclencher F9 (classeur entier) ou Shift+F9 (feuille active) pour maîtriser le moment du recalcul.
- Limiter la volatilité : remplacez
RANDBETWEEN
parRANDARRAY
(une fois), évitezOFFSET/INDIRECT
quand c’est possible, préférez des références structurées stables. - Isoler les blocs : placez paramètres, tirages et calculs dans des plages dédiées ; plus vos dépendances sont « rectangulaires et indépendantes », mieux Excel peut distribuer les threads.
Quand Excel n’est plus le bon outil
- Au‑delà d’environ 1 million d’itérations ou de modèles très emboîtés, Excel devient un prototype plus qu’un moteur de simulation.
- Pour des analyses massives ou récurrentes, migrez la boucle vers Python, R, Julia ou C/C++ (appelés depuis Power Query, Power BI ou Python in Excel) et ramenez uniquement les indicateurs clés dans Excel.
- Les add‑ins spécialisés (p. ex. risk engines) apportent générateurs, distributions et fonctions de risque optimisées.
Bonnes pratiques Monte‑Carlo dans Excel
- Un seul générateur : créez tous les aléas via une seule formule (
RANDARRAY
) puis transformez en valeurs si nécessaire. - Bloc indépendant : paramètre d’itérations, tirages, logique de gain/perte et agrégats dans des zones distinctes. Ce découpage favorise le multithreading.
- Écriture en bloc : si vous utilisez VBA, collectez les résultats dans un tableau et écrivez en une fois.
- Mesurez : minutez vos variantes (F9, chronomètre VBA) et retenez la plus simple qui atteint l’objectif.
Mini‑benchmark indicatif
Les chiffres varient selon les machines et modèles, mais l’ordre de grandeur observé sur 100 000 itérations :
Approche | Temps (approx.) | Utilisation CPU | Commentaires |
---|---|---|---|
Table de données + RANDBETWEEN | 30–120 s | ~10–20 % (1 cœur occupé) | Recalcule la chaîne à chaque scénario |
Formule dynamique (RANDARRAY + BYROW) | 2–8 s | Plusieurs cœurs occasionnellement | Un seul bloc massif, efficace en mémoire |
VBA (boucle en mémoire + écriture en bloc) | 1–5 s | 1 cœur saturé | Contournement du moteur de dépendances |
Python in Excel (NumPy) | 0,5–2 s | Bonne vectorisation | Renvoie un tableau agrégé, peu de trafic Excel |
À retenir : le profil CPU faible ne signifie pas que le PC « bâille », mais que la charge est cantonnée à un seul thread. Le gain vient d’une refonte de la méthode, pas d’un réglage caché.
Procédure de diagnostic rapide
- Identifiez les zones volatiles : sélectionnez la feuille, recherchez
RAND
,RANDBETWEEN
,OFFSET
,INDIRECT
. - Testez sans table de données : refaites la simulation avec une formule matricielle. Comparez le temps.
- Figez les tirages : copiez/collez en valeurs. Le temps s’effondre ? Alors la volatilité était la cause.
- Isoler / bloquer : déplacez tirages et calculs dans des plages dédiées et observez si le multithread s’active (hausse d’utilisation CPU).
- Essayez VBA : exécutez la macro ci‑dessus et comparez.
- Test multi‑instances : lancez 2–4 Excel avec des parts d’itérations. Additionnez les temps.
FAQ
« À quoi sert “Calcul multithread” si je ne vois qu’un cœur utilisé ? »
Le multithreading d’Excel fonctionne quand il existe des blocs indépendants ou des fonctions marquées « thread‑safe ». Les tables de données rejouent le modèle séquentiellement ; vous n’y verrez donc pas plusieurs cœurs saturés.
« Puis‑je forcer une table de données à s’exécuter sur plusieurs cœurs ? »
Non. La parallélisation d’une table de données n’est pas prise en charge. Les alternatives : formules dynamiques, VBA, Python, ou plusieurs instances d’Excel en parallèle avec consolidation.
« Pourquoi Windows affiche 15 % de CPU alors que j’ai 12–24 cœurs ? »
Parce qu’un seul thread (≈ un cœur logique) bosse. Selon l’hyper‑threading et la distinction P‑cores/E‑cores, 100 % d’un thread équivaut souvent à 5–15 % du total du processeur.
« 64 bits rend‑il une table de données plus rapide ? »
Pas en soi. 64 bits augmente l’espace mémoire adressable (utile pour de très grands modèles) mais ne rend pas un calcul intrinsèquement mono‑thread plus rapide.
« Le GPU ou “accélération graphique” aide‑t‑il ?
Non pour le calcul. Cette option concerne surtout le rendu de l’interface, pas le moteur de calcul.
Checklist d’optimisation prête à l’emploi
- Remplacez la table de données par une formule dynamique unique qui génère N tirages et calcule les sorties.
- Figez les séries aléatoires avant d’enchaîner les analyses (modèle non volatil).
- Basculer en Calcul manuel, ne recalculer que quand nécessaire.
- Isoler paramètres, tirages, logique et agrégats dans des blocs indépendants.
- Pour les très gros volumes : migrez la boucle vers VBA (écriture en bloc) ou Python in Excel.
- Besoin de paralléliser coûte que coûte ? Répartissez sur plusieurs instances d’Excel et consolidez.
Exemple complet avec formules dynamiques
Objectif : simuler N parties, calculer moyenne, écart‑type et histogramme, sans table de données.
- En
B1
: le nombre d’itérations (ex. 100000). - En
B3
(sommes) :
=LET(
n; $B$1;
tirages; RANDARRAY(n; 2; 1; 6; VRAI);
BYROW(tirages; LAMBDA(r; SUM(r)))
)
- En
D3
(statistiques) :
=LET(
s; $B$3#;
VSTACK(
{"Indicateur"\"Valeur"};
{"Moyenne"\ MOYENNE(s)};
{"Écart-type"\ ECARTYPE.P(s)};
{"Min"\ MIN(s)};
{"Max"\ MAX(s)}
)
)
- En
F3
(histogramme 2..12) :
=LET(
s; $B$3#;
k; SEQUENCE(11; ; 2);
freq; MAP(k; LAMBDA(x; NB.SI(s; x)));
VSTACK({"Somme"\"Comptage"}; HSTACK(k; freq))
)
Ces trois blocs suffisent pour générer, décrire et agréger la simulation, sans aucune table de données.
Conclusion
Si Excel plafonne à ~15 % de CPU pendant un Monte‑Carlo, ce n’est pas un bug : la table de données et la volatilité forcent une exécution monothread. L’option « Calcul multithread » n’accélère que des blocs indépendants et des fonctions thread‑safe. Les gains significatifs viennent d’un changement d’approche : formules matricielles dynamiques, tirages générés une seule fois, boucle en VBA avec écriture en bloc, Python in Excel, ou parallélisation par plusieurs instances.
En bref : réduisez la volatilité, regroupez le calcul, isolez les blocs. Votre CPU vous dira merci.