2013-04-27 8 views
8

Also, ich habe im Allgemeinen ein ziemlich gutes Verständnis davon, wie die Global Interpreter Lock (GIL) in Python funktioniert. Im Wesentlichen, während der Interpreter läuft, hält ein Thread die GIL für N Ticks (wobei N kann eingestellt werden mit sys.setcheckinterval), zu welchem ​​Zeitpunkt die GIL freigegeben ist und ein anderer Thread die GIL erwerben kann. Das passiert auch, wenn ein Thread eine E/A-Operation startet.Python: GIL Kontext - Switching

Worüber ich etwas verwirrt bin, ist, wie das alles mit C-Erweiterungsmodulen funktioniert.

Wenn Sie ein C-Erweiterungsmodul haben, das die GIL erwirbt und dann einen Python-Code mit PyEval_EvalCode ausführt, kann der Interpreter die GIL freigeben und sie einem anderen Thread geben? Oder wird der C-Thread, der die GIL erworben hat, die GIL dauerhaft behalten, bis PyEval_EvalCode zurückkehrt und die GIL explizit in C freigegeben wird?

PyGILState gstate = PyGILState_Ensure(); 

.... 

/* Can calling PyEval_EvalCode release the GIL and let another thread acquire it?? */ 
PyObject* obj = PyEval_EvalCode(code, global_dict, local_dict); 

PyGILState_Release(gstate); 

Antwort

2

Ja, der Interpreter kann immer die GIL freigeben; es wird es einem anderen Thread geben, nachdem es genügend Anweisungen interpretiert hat, oder automatisch, wenn es einige I/O-Operationen ausführt. Beachten Sie, dass seit dem letzten Python 3.x die Kriterien nicht mehr auf der Anzahl der ausgeführten Anweisungen basieren, sondern darauf, ob genügend Zeit verstrichen ist.

Um einen anderen Effekt zu erhalten, benötigen Sie eine Möglichkeit, die GIL im "atomaren" Modus zu erhalten, indem Sie die GIL erst freigeben, wenn Sie sie explizit freigeben. Dies ist bisher nicht möglich (siehe jedoch https://bitbucket.org/arigo/cpython-withatomic für eine experimentelle Version).

+0

Siehe meine [verwandte Frage] (http://stackoverflow.com/questions/29317120/forcing-a-thread-to-block-all-other-threads-from-executing). Ich verstehe nicht, wie Sie die scheinbare Inkonsistenz zwischen Ihrer Aussage und der Aussage in Python Cookbook lösen können. – max

+0

Siehe [Alberts Antwort] (http://stackoverflow.com/a/29328066). –

1

Wie Armin sagte, kann die GIL innerhalb PyEval_EvalCode freigegeben werden. Wenn es zurückkommt, wird es natürlich wieder erworben.

Der beste Weg ist nur sicherzustellen, dass Ihr Code damit umgehen kann. ZB inkrementieren Sie alle Objekte, in denen Sie C-Zeiger haben, bevor die GIL freigegeben werden könnte. Seien Sie vorsichtig, wenn es Fälle geben könnte, in denen der Python-Code die gleiche Funktion erneut aufruft. Wenn Sie dort einen anderen Mutex haben, können Sie leicht in einen Dead-Lock geraten. Verwenden Sie rekursiv-sichere Mutexe, und während Sie darauf warten, sollten Sie die GIL freigeben, damit der ursprüngliche Thread solche Mutexe freigeben kann.