Loïc Chevalier
← Tous les articles

Optimiser des traitements scientifiques en Python

Vectorisation NumPy, multiprocessing et bonnes pratiques pour accélérer vos pipelines de calcul scientifique.

PythonNumPyPerformanceScientific Computing

Optimiser des traitements scientifiques en Python

Python est devenu le langage de référence pour le calcul scientifique et l'ingénierie. Mais sa réputation de lenteur est-elle méritée ? Pas si l'on utilise les bons outils.

Le problème : les boucles Python

Le piège classique consiste à écrire du code Python "comme du C" :

import numpy as np

# ❌ Lent : boucle Python explicite
def compute_slow(data):
    result = np.zeros(len(data))
    for i in range(len(data)):
        result[i] = data[i] ** 2 + 2 * data[i] + 1
    return result

Sur un tableau de 10 millions d'éléments, cette approche prend plusieurs secondes.

La solution : la vectorisation NumPy

NumPy exécute les opérations en C sous le capot. En éliminant la boucle Python, on obtient des gains de performance considérables :

# ✅ Rapide : opérations vectorisées
def compute_fast(data):
    return data ** 2 + 2 * data + 1

Le gain typique est de 50x à 200x selon les opérations.

Aller plus loin : multiprocessing

Pour les traitements embarrassingly parallel (traitement de fichiers, simulations indépendantes), le module multiprocessing permet d'exploiter tous les cœurs :

from multiprocessing import Pool
from pathlib import Path

def process_file(filepath: Path) -> dict:
    """Traite un fichier de simulation et retourne les métriques."""
    data = np.loadtxt(filepath)
    return {
        "file": filepath.name,
        "mean": float(np.mean(data)),
        "std": float(np.std(data)),
        "max": float(np.max(data)),
    }

files = list(Path("results/").glob("*.dat"))

with Pool() as pool:
    results = pool.map(process_file, files)

Règles pratiques

  1. Profiler avant d'optimiser — utilisez cProfile ou line_profiler pour identifier les vrais goulots d'étranglement.
  2. Vectoriser d'abord — remplacez les boucles par des opérations NumPy. C'est souvent suffisant.
  3. Multiprocessing pour l'I/O et le batch — traitement de fichiers, simulations indépendantes.
  4. Considérer Rust ou C++ pour les cas critiques — via pyo3 ou ctypes, pour les kernels de calcul irréductibles.

Conclusion

Python n'est pas lent — le code Python naïf l'est. Avec la vectorisation NumPy et le multiprocessing, on couvre 95% des besoins d'optimisation en calcul scientifique. Pour les 5% restants, l'interfaçage avec Rust ou C++ offre une solution élégante sans sacrifier l'écosystème Python.