Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 311 – Simplified Global Interpreter Lock Acquisition for Extensions

Author:
Mark Hammond <mhammond at skippinet.com.au>
Status:
Final
Type:
Standards Track
Created:
05-Feb-2003
Python-Version:
2.3
Post-History:
05-Feb-2003, 14-Feb-2003, 19-Apr-2003

Table of Contents

Abstract

This PEP proposes a simplified API for access to the GlobalInterpreter Lock (GIL) for Python extension modules.Specifically, it provides a solution for authors of complexmulti-threaded extensions, where the current state of Python(i.e., the state of the GIL is unknown.

This PEP proposes a new API, for platforms built with threadingsupport, to manage the Python thread state. An implementationstrategy is proposed, along with an initial, platform independentimplementation.

Rationale

The current Python interpreter state API is suitable for simple,single-threaded extensions, but quickly becomes incredibly complexfor non-trivial, multi-threaded extensions.

Currently Python provides two mechanisms for dealing with the GIL:

  • Py_BEGIN_ALLOW_THREADS andPy_END_ALLOW_THREADS macros.These macros are provided primarily to allow a simple Pythonextension that already owns the GIL to temporarily release itwhile making an “external” (ie, non-Python), generallyexpensive, call. Any existing Python threads that are blockedwaiting for the GIL are then free to run. While this is finefor extensions making calls from Python into the outside world,it is no help for extensions that need to make calls into Pythonwhen the thread state is unknown.
  • PyThreadState andPyInterpreterState APIs.These API functions allow an extension/embedded application toacquire the GIL, but suffer from a serious boot-strappingproblem - they require you to know the state of the Pythoninterpreter and of the GIL before they can be used. Oneparticular problem is for extension authors that need to dealwith threads never before seen by Python, but need to callPython from this thread. It is very difficult, delicate anderror prone to author an extension where these “new” threadsalways know the exact state of the GIL, and therefore canreliably interact with this API.

For these reasons, the question of how such extensions shouldinteract with Python is quickly becoming a FAQ. The main impetusfor this PEP, a thread on python-dev[1], immediately identifiedthe following projects with this exact issue:

  • The win32all extensions
  • Boost
  • ctypes
  • Python-GTK bindings
  • Uno
  • PyObjC
  • Mac toolbox
  • PyXPCOM

Currently, there is no reasonable, portable solution to thisproblem, forcing each extension author to implement their ownhand-rolled version. Further, the problem is complex, meaningmany implementations are likely to be incorrect, leading to avariety of problems that will often manifest simply as “Python hashung”.

While the biggest problem in the existing thread-state API is thelack of the ability to query the current state of the lock, it isfelt that a more complete, simplified solution should be offeredto extension authors. Such a solution should encourage authors toprovide error-free, complex extension modules that take fulladvantage of Python’s threading mechanisms.

Limitations and Exclusions

This proposal identifies a solution for extension authors withcomplex multi-threaded requirements, but that only require asingle “PyInterpreterState”. There is no attempt to cater forextensions that require multiple interpreter states. At the timeof writing, no extension has been identified that requiresmultiple PyInterpreterStates, and indeed it is not clear if thatfacility works correctly in Python itself.

This API will not perform automatic initialization of Python, orinitialize Python for multi-threaded operation. Extension authorsmust continue to callPy_Initialize(), and for multi-threadedapplications,PyEval_InitThreads(). The reason for this is thatthe first thread to callPyEval_InitThreads() is nominated as the“main thread” by Python, and so forcing the extension author tospecify the main thread (by requiring them to make this first call)removes ambiguity. AsPy_Initialize() must be called beforePyEval_InitThreads(), and as both of these functions currentlysupport being called multiple times, the burden this places onextension authors is considered reasonable.

It is intended that this API be all that is necessary to acquirethe Python GIL. Apart from the existing, standardPy_BEGIN_ALLOW_THREADS andPy_END_ALLOW_THREADS macros, it isassumed that no additional thread state API functions will be usedby the extension. Extensions with such complicated requirementsare free to continue to use the existing thread state API.

Proposal

This proposal recommends a new API be added to Python to simplifythe management of the GIL. This API will be available on allplatforms built withWITH_THREAD defined.

The intent is that assuming Python has correctly been initialized,an extension author be able to use a small, well-defined “prologuedance”, at any time and on any thread, which will ensure Pythonis ready to be used on that thread. After the extension hasfinished with Python, it must also perform an “epilogue dance” torelease any resources previously acquired. Ideally, these dancescan be expressed in a single line.

Specifically, the following new APIs are proposed:

/*EnsurethatthecurrentthreadisreadytocallthePythonCAPI,regardlessofthecurrentstateofPython,orofitsthreadlock.ThismaybecalledasmanytimesasdesiredbyathreadsolongaseachcallismatchedwithacalltoPyGILState_Release().Ingeneral,otherthread-stateAPIsmaybeusedbetween_Ensure()and_Release()calls,solongasthethread-stateisrestoredtoitspreviousstatebeforetheRelease().Forexample,normaluseofthePy_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADSmacrosareacceptable.Thereturnvalueisanopaque"handle"tothethreadstatewhenPyGILState_Acquire()wascalled,andmustbepassedtoPyGILState_Release()toensurePythonisleftinthesamestate.Eventhoughrecursivecallsareallowed,thesehandlescan*not*beshared-eachuniquecalltoPyGILState_EnsuremustsavethehandleforitscalltoPyGILState_Release.Whenthefunctionreturns,thecurrentthreadwillholdtheGIL.Failureisafatalerror.*/PyAPI_FUNC(PyGILState_STATE)PyGILState_Ensure(void);/*Releaseanyresourcespreviouslyacquired.Afterthiscall,Python'sstatewillbethesameasitwaspriortothecorrespondingPyGILState_Acquirecall(butgenerallythisstatewillbeunknowntothecaller,hencetheuseoftheGILStateAPI.)EverycalltoPyGILState_EnsuremustbematchedbyacalltoPyGILState_Releaseonthesamethread.*/PyAPI_FUNC(void)PyGILState_Release(PyGILState_STATE);

Common usage will be:

voidSomeCFunction(void){/*ensureweholdthelock*/PyGILState_STATEstate=PyGILState_Ensure();/*UsethePythonAPI*/.../*RestorethestateofPython*/PyGILState_Release(state);}

Design and Implementation

The general operation ofPyGILState_Ensure() will be:

  • assert Python is initialized.
  • Get aPyThreadState for the current thread, creating and savingif necessary.
  • remember the current state of the lock (owned/not owned)
  • If the current state does not own the GIL, acquire it.
  • Increment a counter for how many calls toPyGILState_Ensure have beenmade on the current thread.
  • return

The general operation ofPyGILState_Release() will be:

  • assert our thread currently holds the lock.
  • If old state indicates lock was previously unlocked, release GIL.
  • Decrement thePyGILState_Ensure counter for the thread.
  • If counter == 0:
    • release and delete thePyThreadState.
    • forget theThreadState as being owned by the thread.
  • return

It is assumed that it is an error if two discretePyThreadStatesare used for a single thread. Comments inpystate.h (“Stateunique per thread”) support this view, although it is neverdirectly stated. Thus, this will require some implementation ofThread Local Storage. Fortunately, a platform independentimplementation of Thread Local Storage already exists in thePython source tree, in the SGI threading port. This code will beintegrated into the platform independent Python core, but in sucha way that platforms can provide a more optimal implementation ifdesired.

Implementation

An implementation of this proposal can be found athttps://bugs.python.org/issue684256

References

[1]
David Abrahams, Extension modules, Threading, and the GILhttps://mail.python.org/pipermail/python-dev/2002-December/031424.html

Copyright

This document has been placed in the public domain.


Source:https://github.com/python/peps/blob/main/peps/pep-0311.rst

Last modified:2025-02-01 08:59:27 GMT


[8]ページ先頭

©2009-2025 Movatter.jp