Skip to content

PyEval_InitThreads in Python 3: Wie/wann soll ich es aufrufen? (die Saga geht bis zum Überdruss weiter)

Nachdem wir in verschiedenen Repositories und Internetforen gesucht haben, haben wir endlich die Antwort gefunden, die wir Ihnen jetzt zeigen werden.

Lösung:

Ihr Verständnis ist richtig: Das Aufrufen von PyEval_InitThreads erwirbt u.a. die GIL. In einer korrekt geschriebenen Python/C-Anwendung ist dies kein Problem, da die GIL rechtzeitig freigeschaltet wird, entweder automatisch oder manuell.

Wenn der Haupt-Thread mit der Ausführung von Python-Code fortfährt, gibt es nichts Besonderes zu tun, da der Python-Interpreter die GIL nach der Ausführung einer Reihe von Anweisungen automatisch wieder freigibt (so dass ein anderer Thread sie übernehmen kann, der sie wiederum freigibt usw.). Außerdem gibt Python die GIL immer dann frei, wenn ein blockierender Systemaufruf ansteht, z.B. um aus dem Netzwerk zu lesen oder in eine Datei zu schreiben, um den Aufruf herum.

Die ursprüngliche Version dieser Antwort endete ziemlich genau hier. Aber es gibt noch eine weitere Sache, die zu berücksichtigen ist: die Einbettung . Szenario.

Beim Einbetten von Python initialisiert der Haupt-Thread oft Python und führt dann andere, nicht Python bezogene Aufgaben aus. In diesem Szenario gibt es nichts, was automatisch die GIL freigeben, so dass dies vom Thread selbst erledigt werden muss. Das ist in keiner Weise spezifisch für den Aufruf, der die PyEval_InitThreadsaufruft, es wird von jedem Python/C-Code erwartet, der mit der erworbenen GIL aufgerufen wird.

Zum Beispiel kann der main() Code wie diesen enthalten:

Py_Initialize();
PyEval_InitThreads();

Py_BEGIN_ALLOW_THREADS
... call the non-Python part of the application here ...
Py_END_ALLOW_THREADS

Py_Finalize();

Wenn Ihr Code Threads manuell erstellt, müssen sie die GIL erwerben, bevor sie irgendetwas Python-bezogenes tun, selbst so einfach wie Py_INCREF. Um dies zu tun, verwenden Sie das Folgende:

// Acquire the GIL
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

... call Python code here ...

// Release the GIL. No Python API allowed beyond this point.
PyGILState_Release(gstate);

Ich habe ähnliche Symptome wie Sie beobachtet: Deadlocks, wenn ich nur PyEval_InitThreads() aufrufe, weil mein Hauptthread nie wieder etwas von Python aufruft, und Segfaults, wenn ich etwas wie PyEval_SaveThread() bedingungslos aufrufe. Die Symptome hängen von der Python-Version und von der Situation ab: Ich entwickle ein Plug-in, das Python für eine Bibliothek einbettet, die als Teil einer Python-Erweiterung geladen werden kann. Der Code muss also unabhängig davon laufen, ob er von Python als Main geladen wird.

Das Folgende hat bei mir sowohl mit Python 2.7 als auch mit Python 3.4 funktioniert, und zwar sowohl mit meiner Bibliothek innerhalb als auch außerhalb von Python. In meiner Plug-in-Init-Routine, die im Hauptthread ausgeführt wird, führe ich aus:

  Py_InitializeEx(0);
  if (!PyEval_ThreadsInitialized()) {
    PyEval_InitThreads();
    PyThreadState* mainPyThread = PyEval_SaveThread();
  }

(mainPyThread ist eigentlich eine statische Variable, aber ich glaube nicht, dass das wichtig ist, da ich sie nie wieder verwenden muss).

Dann erstelle ich Threads mit pthreads, und in jeder Funktion, die auf die Python-API zugreifen muss, verwende ich:

  PyGILState_STATE gstate;
  gstate = PyGILState_Ensure();
  // Python C API calls
  PyGILState_Release(gstate);

Es gibt zwei Methoden für Multi-Threading bei der Ausführung von C/Python-API.

1. die Ausführung verschiedener Threads mit demselben Interpreter - Wir können einen Python-Interpreter ausführen und denselben Interpreter auf die verschiedenen Threads aufteilen.

Die Kodierung wird wie folgt aussehen.

main(){     
//initialize Python
Py_Initialize();
PyRun_SimpleString("from time import time,ctimen"
    "print 'In Main, Today is',ctime(time())n");

//to Initialize and acquire the global interpreter lock
PyEval_InitThreads();

//release the lock  
PyThreadState *_save;
_save = PyEval_SaveThread();

// Create threads.
for (int i = 0; i
  1. Eine andere Methode ist, dass wir einen Python-Interpreter im Haupt-Thread ausführen und jedem Thread einen eigenen Sub-Interpreter zuweisen können. So läuft jeder Thread mit seinen eigenen, unabhängigen Versionen aller importierten Module, einschließlich der grundlegenden Module - builtins, __main__ und sys.

Der Code sieht folgendermaßen aus

int main()
{

// Initialize the main interpreter
Py_Initialize();
// Initialize and acquire the global interpreter lock
PyEval_InitThreads();
// Release the lock     
PyThreadState *_save;
_save = PyEval_SaveThread();

// create threads
for (int i = 0; i

Es ist zu beachten, dass die globale Interpreter-Sperre immer noch besteht und wir trotz der Vergabe von individuellen Interpretern an jeden Thread immer noch nur einen Thread zur gleichen Zeit ausführen können, wenn es um die Ausführung von Python geht. GIL ist . UNIQUE zu PROZESS Trotz der Bereitstellung eines eigenen Subinterpreters für jeden Thread können wir also keine gleichzeitige Ausführung von Threads haben.

Quellen: Ausführung eines Python-Interpreters im Haupt-Thread und für jeden Thread können wir einen eigenen Sub-Interpreter bereitstellen

Multi-Threading-Tutorial (msdn)

Bewertungen und Kommentare

Wir laden Sie ein, unseren Inhalten einen Mehrwert zu verleihen, indem Sie Ihr Dienstalter in den Anmerkungen mit einbeziehen.



Nutzen Sie unsere Suchmaschine

Suche
Generic filters

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.