Thread-Sicherheit in SciPy#
SciPy unterstützt die Verwendung in einem Multithreading-Kontext über das Modul threading in der Standardbibliothek. Viele SciPy-Operationen geben den GIL frei, ebenso wie NumPy (und ein Großteil der SciPy-Funktionalität ist als Aufrufe von NumPy-Funktionen implementiert) – im Gegensatz zu vielen Situationen in Python ist es möglich, die parallele Leistung durch Ausnutzung der Multithreading-Parallelität in Python zu verbessern.
Die einfachsten Leistungsgewinne ergeben sich, wenn jeder Worker-Thread seine eigenen Array- oder Array-Objekt-Sätze besitzt, ohne dass Daten direkt zwischen den Threads geteilt werden. Threads, die die meiste Zeit in Low-Level-Code verbringen, laufen typischerweise parallel.
Es ist möglich, NumPy-Arrays zwischen Threads zu teilen, aber es ist äußerste Vorsicht geboten, um Thread-Sicherheitsprobleme beim Mutieren von Arrays zu vermeiden, die zwischen mehreren Threads geteilt werden – siehe die NumPy-Dokumentation zur Thread-Sicherheit für weitere Details. SciPy-Funktionen mutieren keine Arrays, die der Benutzer übergibt, es sei denn, eine Funktion dokumentiert ausdrücklich, dass sie dies tun wird (was selten ist). Daher ist das Aufrufen von SciPy-Funktionen im Threading-Modus auf demselben NumPy-Array sicher.
Während der Großteil von SciPy aus *Funktionen* besteht, ist bei *Klassen* und *Datenstrukturen* mehr Vorsicht geboten.
Klassen mit Zustand, wie einige der Integrations- und Interpolationsobjekte in scipy.integrate und scipy.interpolate, sind in der Regel robust gegenüber parallelen Aufrufen. Sie akzeptieren entweder parallele Aufrufe oder lösen eine informative Fehlermeldung aus. Zum Beispiel kann scipy.integrate.ode eine IntegratorConcurrencyError für Integrationsmethoden auslösen, die keine parallele Ausführung unterstützen.
SciPy bietet einige Datenstrukturen, nämlich Sparse-Arrays und Matrizen in scipy.sparse und k-D-Bäume in scipy.spatial. Diese Datenstrukturen sind *derzeit nicht thread-sicher*. Vermeiden Sie insbesondere Operationen, die eine Datenstruktur mutieren, wie die Verwendung von Item- oder Slice-Zuweisungen auf Sparse-Arrays, während die Daten über mehrere Threads hinweg gemeinsam genutzt werden. Dies kann zu Datenkorruption, Abstürzen oder anderem unerwünschten Verhalten führen.
Beachten Sie, dass Operationen, die den GIL *nicht* freigeben, keine Leistungsgewinne durch die Verwendung des Moduls threading erzielen und stattdessen besser mit multiprocessing bedient werden könnten.
Free-threaded Python#
Hinzugefügt in Version 1.15.0.
Ab SciPy 1.15.0 und CPython 3.13 bietet SciPy experimentelle Unterstützung für Python-Laufzeiten mit deaktiviertem GIL auf allen Plattformen. Weitere Informationen zur Installation und Verwendung von free-threaded Python finden Sie unter https://py-free-threading.github.io.
Da free-threaded Python keinen globalen Interpreter-Lock (GIL) besitzt, um den Zugriff auf Python-Objekte zu serialisieren, gibt es mehr Möglichkeiten für Threads, gemeinsamen Zustand zu mutieren und Thread-Sicherheitsprobleme zu erzeugen. Die gesamte SciPy-Funktionalität wird für die Verwendung von parallelen Threads getestet, jedoch erwarten wir, dass es noch unentdeckte Probleme geben wird – wenn Sie auf ein Problem stoßen, überprüfen Sie die GitHub-Issues mit dem Label free-threading und eröffnen Sie ein neues Issue, wenn noch keines für die fehlerhafte Funktion existiert.