Die Dokumentation für die Unterstützung von CPython-Threads ist frustrierend widersprüchlich und spärlich.
Im Allgemeinen scheinen sich alle einig zu sein, dass Multithread-C-Anwendungen, die Python einbetten, immer die GIL erwerben müssen, bevor sie den Python-Interpreter aufrufen. Typischerweise geschieht dies durch:
PyGILState_STATE s = PyGILState_Ensure();
/* do stuff with Python */
PyGILState_Release(s);
Die Dokumente schreiben das ziemlich deutlich: https://docs.python.org/2/c-api/init.html#non-python-created-threads
In der Praxis ist es jedoch eine andere Geschichte, ein Multithread-C-Programm zu bekommen, das Python einbettet, um tatsächlich reibungslos zu funktionieren. Es scheint viele Macken und Überraschungen zu geben, auch wenn Sie sich genau an die Dokumentation halten.
Zum Beispiel scheint Python hinter den Kulissen zwischen dem “Haupt-Thread” zu unterscheiden (was meiner Meinung nach der Thread ist, der aufruft Py_Initialize
) und andere Threads. Insbesondere ist jeder Versuch, die GIL zu erwerben und Python-Code im “Haupt”-Thread auszuführen, durchweg fehlgeschlagen, wenn ich dies versuche – (zumindest mit Python 3.x), das Programm bricht mit a ab Fatal Python error: drop_gil: GIL is not locked
Nachricht, die dumm ist, weil natürlich die GIL gesperrt ist!
Beispiel:
int main()
{
Py_Initialize();
PyEval_InitThreads();
PyEval_ReleaseLock();
assert(PyEval_ThreadsInitialized());
PyGILState_STATE s = PyGILState_Ensure();
const char* command = "x = 5\nfor i in range(0,10): print(x*i)";
PyRun_SimpleString(command);
PyGILState_Release(s);
Py_Finalize();
return 0;
}
Dieses einfache Programm bricht mit einem „GIL ist nicht gesperrt“-Fehler ab, obwohl ich es eindeutig gesperrt habe. Wenn ich jedoch einen anderen Thread spawne und versuche, die GIL in diesem Thread zu erwerben, funktioniert alles.
CPython scheint also ein (undokumentiertes) Konzept eines “Hauptthreads” zu haben, das sich irgendwie von sekundären Threads unterscheidet, die von C hervorgebracht werden.
Frage: Ist das irgendwo dokumentiert? Hat jemand irgendwelche Erfahrungen gemacht, die Aufschluss darüber geben würden, was genau die Regeln für den Erwerb der GIL sind, und ob es einen Einfluss darauf haben soll, im “Haupt”-Thread im Vergleich zu einem untergeordneten Thread zu sein?
PS: Das habe ich auch notiert PyEval_ReleaseLock
ist ein veralteter API-Aufruf, aber ich habe noch keine Alternative gesehen, die tatsächlich funktioniert. Wenn Sie nicht anrufen PyEval_ReleaseLock
nach Anruf PyEval_InitThreads
, hängt sich Ihr Programm sofort auf. Allerdings ist die neuere Alternative in den Dokumenten erwähnt, PyEval_SaveThread
hat bei mir in der praxis nie funktioniert – es segnen sofort fehler, zumindest wenn ich es im “haupt”thread aufrufe”.
Diese Frage impliziert, dass Sie PyEval_ReleaseLock überhaupt nicht aufrufen sollten: stackoverflow.com/q/15470367/321772
– Adam
30. Juni 2014 um 22:13 Uhr
Sie sollten wahrscheinlich fragen python-dev.
– Kaleb Hattingh
1. Juli 2014 um 1:09 Uhr