初期化、ファイナライズ、およびスレッド
Python初期化構成も参照してください。
Python初期化前
Pythonを組み込んだアプリケーションでは、他のPython / C API関数を使用する前に、 Py_Initialize()関数を呼び出す必要があります。 いくつかの関数とグローバル構成変数を除いて。
Pythonを初期化する前に、次の関数を安全に呼び出すことができます。
- 構成機能:
- 有益な機能:
- ユーティリティ:
- メモリアロケータ:
ノート
次の関数は、 Py_Initialize()の前にと呼ばれるべきではありません: Py_EncodeLocale()、 Py_GetPath()、 Py_GetPrefix() 、 Py_GetExecPrefix()、 Py_GetProgramFullPath()、 Py_GetPythonHome()、 Py_GetProgramName()、 PyEval_In 。
グローバル構成変数
Pythonには、さまざまな機能やオプションを制御するためのグローバル構成用の変数があります。 デフォルトでは、これらのフラグはコマンドラインオプションによって制御されます。
オプションでフラグを設定する場合、フラグの値はオプションが設定された回数です。 たとえば、-b
は Py_BytesWarningFlag を1に設定し、-bb
は Py_BytesWarningFlag を2に設定します。
- int Py_BytesWarningFlag
bytes または bytearray を str または bytes と int と比較するときに警告を発行します。
2
以上の場合はエラーを発行します。-b オプションで設定します。
- int Py_DebugFlag
パーサーのデバッグ出力をオンにします(コンパイルオプションに応じて、エキスパートのみ)。
-d オプションと PYTHONDEBUG 環境変数によって設定されます。
- int Py_DontWriteBytecodeFlag
ゼロ以外に設定すると、Pythonはソースモジュールのインポート時に
.pyc
ファイルを書き込もうとしません。-B オプションと PYTHONDONTWRITEBYTECODE 環境変数によって設定されます。
- int Py_FrozenFlag
Py_GetPath()でモジュール検索パスを計算するときのエラーメッセージを抑制します。
_freeze_importlib
およびfrozenmain
プログラムで使用されるプライベートフラグ。
- int Py_HashRandomizationFlag
PYTHONHASHSEED 環境変数が空でない文字列に設定されている場合は、
1
に設定します。フラグがゼロ以外の場合は、 PYTHONHASHSEED 環境変数を読み取って、シークレットハッシュシードを初期化します。
- int Py_IgnoreEnvironmentFlag
すべての
PYTHON*
環境変数を無視します。 PYTHONPATH および PYTHONHOME 、設定されている可能性があります。
- int Py_InspectFlag
スクリプトが最初の引数として渡されるか、 -c オプションが使用される場合、 sys.stdin がターミナル。
-i オプションと PYTHONINSPECT 環境変数によって設定されます。
- int Py_InteractiveFlag
- -i オプションで設定します。
- int Py_IsolatedFlag
Pythonを分離モードで実行します。 分離モードでは、 sys.path には、スクリプトのディレクトリもユーザーのサイトパッケージディレクトリも含まれていません。
-I オプションで設定します。
バージョン3.4の新機能。
- int Py_LegacyWindowsFSEncodingFlag
フラグがゼロ以外の場合は、ファイルシステムエンコーディングにUTF-8エンコーディングの代わりに
mbcs
エンコーディングを使用します。PYTHONLEGACYWINDOWSFSENCODING 環境変数が空でない文字列に設定されている場合は、
1
に設定します。詳細については、 PEP 529 を参照してください。
- int Py_LegacyWindowsStdioFlag
フラグがゼロ以外の場合は、 sys 標準ストリームに
WindowsConsoleIO
の代わりに io.FileIO を使用します。PYTHONLEGACYWINDOWSSTDIO 環境変数が空でない文字列に設定されている場合は、
1
に設定します。詳細については、 PEP 528 を参照してください。
- int Py_NoSiteFlag
モジュール site のインポートと、それに伴う sys.path のサイト依存の操作を無効にします。 また、 site が後で明示的にインポートされる場合は、これらの操作を無効にします(トリガーする場合は、 site.main()を呼び出します)。
-S オプションで設定します。
- int Py_NoUserSiteDirectory
ユーザーサイトパッケージディレクトリを sys.path に追加しないでください。
-s および -I オプション、および PYTHONNOUSERSITE 環境変数によって設定されます。
- int Py_OptimizeFlag
- -O オプションと PYTHONOPTIMIZE 環境変数によって設定されます。
- int Py_QuietFlag
インタラクティブモードでも、著作権とバージョンのメッセージを表示しないでください。
-q オプションで設定します。
バージョン3.2の新機能。
- int Py_UnbufferedStdioFlag
stdoutストリームとstderrストリームを強制的にバッファリング解除します。
-u オプションと PYTHONUNBUFFERED 環境変数によって設定されます。
- int Py_VerboseFlag
モジュールが初期化されるたびにメッセージを出力し、モジュールがロードされた場所(ファイル名または組み込みモジュール)を示します。
2
以上の場合は、モジュールの検索時にチェックされるファイルごとにメッセージを出力します。 終了時のモジュールのクリーンアップに関する情報も提供します。-v オプションと PYTHONVERBOSE 環境変数によって設定されます。
インタプリタの初期化と終了
- void Py_Initialize()
Pythonインタープリターを初期化します。 Pythonを組み込んだアプリケーションでは、他のPython / CAPI関数を使用する前にこれを呼び出す必要があります。 いくつかの例外については、 Python初期化前を参照してください。
これにより、ロードされたモジュール(
sys.modules
)のテーブルが初期化され、基本モジュール builtins 、 __ main __ 、および sys が作成されます。 また、モジュール検索パス(sys.path
)を初期化します。sys.argv
は設定されません。 そのためには PySys_SetArgvEx()を使用してください。 これは、( Py_FinalizeEx()を最初に呼び出さずに)2回目に呼び出された場合はノーオペレーションです。 戻り値はありません。 初期化が失敗した場合、致命的なエラーになります。ノート
Windowsで、コンソールモードを
O_TEXT
からO_BINARY
に変更します。これは、Cランタイムを使用したコンソールのPython以外の使用にも影響します。
- void Py_InitializeEx(int initsigs)
- この関数は、 initsigs が
1
の場合、 Py_Initialize()のように機能します。 initsigs が0
の場合、シグナルハンドラーの初期化登録をスキップします。これは、Pythonが組み込まれている場合に役立つことがあります。
- int Py_IsInitialized()
- Pythonインタープリターが初期化されている場合はtrue(ゼロ以外)を返し、そうでない場合はfalse(ゼロ)を返します。 Py_FinalizeEx()が呼び出された後、 Py_Initialize()が再度呼び出されるまで、これはfalseを返します。
- int Py_FinalizeEx()
Py_Initialize()によって行われたすべての初期化とその後のPython / C API関数の使用を元に戻し、作成されてまだ破棄されていないすべてのサブインタープリター(以下の Py_NewInterpreter()を参照)を破棄します。 Py_Initialize()の最後の呼び出し以降。 理想的には、これによりPythonインタープリターによって割り当てられたすべてのメモリが解放されます。 これは、2回目に呼び出された場合(最初に Py_Initialize()を再度呼び出さずに)、何も実行されません。 通常、戻り値は
0
です。 ファイナライズ(バッファデータのフラッシュ)中にエラーが発生した場合は、-1
が返されます。この機能は、いくつかの理由で提供されています。 埋め込みアプリケーションは、アプリケーション自体を再起動せずにPythonを再起動したい場合があります。 動的にロード可能なライブラリ(またはDLL)からPythonインタプリタをロードしたアプリケーションは、DLLをアンロードする前に、Pythonによって割り当てられたすべてのメモリを解放したい場合があります。 アプリケーションでのメモリリークのハント中に、開発者はアプリケーションを終了する前にPythonによって割り当てられたすべてのメモリを解放したい場合があります。
バグと警告:モジュールとモジュール内のオブジェクトの破棄はランダムな順序で行われます。 これにより、デストラクタ(
__del__()
メソッド)が他のオブジェクト(関数でさえ)またはモジュールに依存している場合に失敗する可能性があります。 Pythonによってロードされた動的にロードされた拡張モジュールはアンロードされません。 Pythonインタープリターによって割り当てられた少量のメモリが解放されない場合があります(リークを見つけた場合は、報告してください)。 オブジェクト間の循環参照に拘束されているメモリは解放されません。 拡張モジュールによって割り当てられた一部のメモリは解放されない場合があります。 一部の拡張機能は、初期化ルーチンが複数回呼び出されると正しく機能しない場合があります。 これは、アプリケーションが Py_Initialize()と Py_FinalizeEx()を複数回呼び出す場合に発生する可能性があります。バージョン3.6の新機能。
- void Py_Finalize()
- これは、戻り値を無視する Py_FinalizeEx()の下位互換性のあるバージョンです。
プロセス全体のパラメータ
- int Py_SetStandardStreamEncoding(const char *encoding, const char *errors)
この関数が呼び出された場合は、 Py_Initialize()の前に呼び出す必要があります。 str.encode()と同じ意味で、標準IOで使用するエンコーディングとエラー処理を指定します。
PYTHONIOENCODING 値をオーバーライドし、環境変数が機能しない場合に埋め込みコードでIOエンコーディングを制御できるようにします。
エンコーディングおよび/またはエラーは、 PYTHONIOENCODING および/またはデフォルト値(他の設定に応じて)を使用するために
NULL
である可能性があります)。sys.stderr は、この(または他の)設定に関係なく、常に「backslashreplace」エラーハンドラーを使用することに注意してください。
Py_FinalizeEx()が呼び出された場合、 Py_Initialize()への後続の呼び出しに影響を与えるために、この関数を再度呼び出す必要があります。
成功した場合は
0
を返し、エラーの場合はゼロ以外の値を返します(例: インタプリタがすでに初期化された後に呼び出す)。バージョン3.4の新機能。
- void Py_SetProgramName(const wchar_t *name)
この関数は、 Py_Initialize()が初めて呼び出される場合は、呼び出す前に呼び出す必要があります。 プログラムの
main()
関数のargv[0]
引数の値をインタープリターに通知します(ワイド文字に変換されます)。 これは、 Py_GetPath()および以下の他のいくつかの関数によって使用され、インタープリター実行可能ファイルに関連するPythonランタイムライブラリを検索します。 デフォルト値は'python'
です。 引数は、静的ストレージ内のゼロで終了するワイド文字ストリングを指している必要があります。このストリングの内容は、プログラムの実行中に変更されません。 Pythonインタープリターのコードは、このストレージの内容を変更しません。Py_DecodeLocale()を使用してバイト文字列をデコードし、 wchar _ * 文字列を取得します。
- wchar *Py_GetProgramName()
- Py_SetProgramName()で設定されたプログラム名、またはデフォルトを返します。 返された文字列は静的ストレージを指します。 呼び出し元はその値を変更しないでください。
- wchar_t *Py_GetPrefix()
- インストールされているプラットフォームに依存しないファイルのプレフィックスを返します。 これは、 Py_SetProgramName()で設定されたプログラム名といくつかの環境変数からのいくつかの複雑なルールから導き出されます。 たとえば、プログラム名が
'/usr/local/bin/python'
の場合、プレフィックスは'/usr/local'
です。 返された文字列は静的ストレージを指します。 呼び出し元はその値を変更しないでください。 これは、ビルド時の configure スクリプトのトップレベルMakefile
の prefix 変数と--prefix
引数に対応します。 この値は、Pythonコードでsys.prefix
として使用できます。 Unixでのみ役立ちます。 次の関数も参照してください。
- wchar_t *Py_GetExecPrefix()
インストールされているプラットフォーム依存ファイルの exec-prefix を返します。 これは、 Py_SetProgramName()で設定されたプログラム名といくつかの環境変数からのいくつかの複雑なルールから導き出されます。 たとえば、プログラム名が
'/usr/local/bin/python'
の場合、execプレフィックスは'/usr/local'
です。 返された文字列は静的ストレージを指します。 呼び出し元はその値を変更しないでください。 これは、ビルド時のトップレベルMakefile
の exec_prefix 変数および configure スクリプトの--exec-prefix
引数に対応します。 この値は、Pythonコードでsys.exec_prefix
として使用できます。 Unixでのみ役立ちます。背景:プラットフォームに依存するファイル(実行可能ファイルや共有ライブラリなど)が別のディレクトリツリーにインストールされている場合、exec-prefixはプレフィックスとは異なります。 通常のインストールでは、プラットフォームに依存するファイルは
/usr/local/plat
サブツリーにインストールされ、プラットフォームに依存しないファイルは/usr/local
にインストールされます。一般的に言えば、プラットフォームはハードウェアとソフトウェアのファミリの組み合わせです。 Solaris 2.xオペレーティングシステムを実行しているSparcマシンは同じプラットフォームと見なされますが、Solaris 2.xを実行しているIntelマシンは別のプラットフォームであり、Linuxを実行しているIntelマシンはさらに別のプラットフォームです。 同じオペレーティングシステムの異なるメジャーリビジョンも、通常、異なるプラットフォームを形成します。 非Unixオペレーティングシステムは別の話です。 これらのシステムでのインストール戦略は非常に異なるため、プレフィックスとexec-prefixは無意味であり、空の文字列に設定されます。 コンパイルされたPythonバイトコードファイルはプラットフォームに依存しないことに注意してください(ただし、コンパイルされたPythonバージョンからは独立していません!)。
システム管理者は、
/usr/local/plat
をプラットフォームごとに異なるファイルシステムとして、プラットフォーム間で/usr/local
を共有するように mount または automount プログラムを構成する方法を知っています。
- wchar_t *Py_GetProgramFullPath()
- Python実行可能ファイルの完全なプログラム名を返します。 これは、プログラム名(上記の Py_SetProgramName()で設定)からデフォルトのモジュール検索パスを導出することの副作用として計算されます。 返された文字列は静的ストレージを指します。 呼び出し元はその値を変更しないでください。 この値は、Pythonコードで
sys.executable
として使用できます。
- wchar_t *Py_GetPath()
- デフォルトのモジュール検索パスを返します。 これは、プログラム名(上記の Py_SetProgramName()で設定)といくつかの環境変数から計算されます。 返される文字列は、プラットフォームに依存する区切り文字で区切られた一連のディレクトリ名で構成されます。 区切り文字は、UnixおよびmacOSでは
':'
、Windowsでは';'
です。 返された文字列は静的ストレージを指します。 呼び出し元はその値を変更しないでください。 リスト sys.path は、インタープリターの起動時にこの値で初期化されます。 モジュールをロードするための検索パスを変更するために、後で変更することができます(通常は変更されます)。
- void Py_SetPath(const wchar_t*)
デフォルトのモジュール検索パスを設定します。 この関数が Py_Initialize()の前に呼び出された場合、 Py_GetPath()はデフォルトの検索パスを計算しようとせず、代わりに提供されたパスを使用します。 これは、Pythonがすべてのモジュールの場所を完全に知っているアプリケーションに組み込まれている場合に役立ちます。 パスコンポーネントは、プラットフォームに依存する区切り文字で区切る必要があります。これは、UnixおよびmacOSでは
':'
、Windowsでは';'
です。これにより、 sys.executable がプログラムのフルパス( Py_GetProgramFullPath()を参照)および sys.prefix および sys.exec_prefixに設定されます。 は空になります。 Py_Initialize()を呼び出した後、必要に応じてこれらを変更するのは呼び出し元の責任です。
Py_DecodeLocale()を使用してバイト文字列をデコードし、 wchar _ * 文字列を取得します。
path引数は内部的にコピーされるため、呼び出しが完了した後、呼び出し元はそれを解放できます。
バージョン3.8で変更:プログラム名の代わりに、プログラムのフルパスが sys.executable に使用されるようになりました。
- const char *Py_GetVersion()
このPythonインタープリターのバージョンを返します。 これは次のような文字列です
"3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
最初の単語(最初のスペース文字まで)は現在のPythonバージョンです。 最初の3文字は、ピリオドで区切られたメジャーバージョンとマイナーバージョンです。 返された文字列は静的ストレージを指します。 呼び出し元はその値を変更しないでください。 この値は、Pythonコードで sys.version として使用できます。
- const char *Py_GetPlatform()
- 現在のプラットフォームのプラットフォーム識別子を返します。 Unixでは、これはオペレーティングシステムの「正式な」名前から形成され、小文字に変換され、その後にメジャーリビジョン番号が続きます。 たとえば、SunOS5.xとしても知られているSolaris2.xの場合、値は
'sunos5'
です。 macOSでは'darwin'
です。 Windowsでは'win'
です。 返された文字列は静的ストレージを指します。 呼び出し元はその値を変更しないでください。 この値は、Pythonコードでsys.platform
として使用できます。
- const char *Py_GetCopyright()
たとえば、現在のPythonバージョンの公式の著作権文字列を返します
'Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam'
返された文字列は静的ストレージを指します。 呼び出し元はその値を変更しないでください。 この値は、Pythonコードで
sys.copyright
として使用できます。
- const char *Py_GetCompiler()
現在のPythonバージョンのビルドに使用されたコンパイラの表示を角かっこで囲んで返します。次に例を示します。
"[GCC 2.7.2.2]"
返された文字列は静的ストレージを指します。 呼び出し元はその値を変更しないでください。 この値は、変数
sys.version
の一部としてPythonコードで使用できます。
- const char *Py_GetBuildInfo()
たとえば、現在のPythonインタープリターインスタンスのシーケンス番号とビルド日時に関する情報を返します。
"#67, Aug 1 1997, 22:34:28"
返された文字列は静的ストレージを指します。 呼び出し元はその値を変更しないでください。 この値は、変数
sys.version
の一部としてPythonコードで使用できます。
- void PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath)
argc と argv に基づいて sys.argv を設定します。 これらのパラメーターは、プログラムの
main()
関数に渡されるパラメーターと似ていますが、最初のエントリがPythonインタープリターをホストする実行可能ファイルではなく、実行されるスクリプトファイルを参照する必要がある点が異なります。 実行されるスクリプトがない場合、 argv の最初のエントリは空の文字列である可能性があります。 この関数が sys.argv の初期化に失敗した場合、 Py_FatalError()を使用して致命的な状態が通知されます。updatepath がゼロの場合、これが関数が実行するすべてです。 updatepath がゼロ以外の場合、関数は次のアルゴリズムに従って sys.path も変更します。
既存のスクリプトの名前が
argv[0]
で渡される場合、スクリプトが配置されているディレクトリの絶対パスが sys.path の前に付加されます。それ以外の場合(つまり、 argc が
0
であるか、argv[0]
が既存のファイル名を指していない場合)、 sys.pathの前に空の文字列が追加されます。これは、現在の作業ディレクトリ("."
)の先頭に追加するのと同じです。
Py_DecodeLocale()を使用してバイト文字列をデコードし、 wchar _ * 文字列を取得します。
ノート
単一のスクリプトを実行する以外の目的でPythonインタープリターを埋め込むアプリケーションは、
0
を updatepath として渡し、必要に応じて sys.path 自体を更新することをお勧めします。 CVE-2008-5983 を参照してください。3.1.3より前のバージョンでは、 PySys_SetArgv()を呼び出した後、最初の sys.path 要素を手動でポップすることで、同じ効果を得ることができます。
PyRun_SimpleString("import sys; sys.path.pop(0)\n");
バージョン3.1.3の新機能。
- void PySys_SetArgv(int argc, wchar_t **argv)
この関数は、 python インタープリターが -I で開始されていない限り、 updatepath が
1
に設定された PySys_SetArgvEx()のように機能します。 ]。Py_DecodeLocale()を使用してバイト文字列をデコードし、 wchar _ * 文字列を取得します。
バージョン3.4で変更: updatepath の値は -I に依存します。
- void Py_SetPythonHome(const wchar_t *home)
デフォルトの「ホーム」ディレクトリ、つまり標準のPythonライブラリの場所を設定します。 引数文字列の意味については、 PYTHONHOME を参照してください。
引数は、静的ストレージ内のゼロで終了する文字列を指している必要があります。この文字列の内容は、プログラムの実行中に変更されません。 Pythonインタープリターのコードは、このストレージの内容を変更しません。
Py_DecodeLocale()を使用してバイト文字列をデコードし、 wchar _ * 文字列を取得します。
- w_char *Py_GetPythonHome()
- デフォルトの「ホーム」、つまり、 Py_SetPythonHome()の前回の呼び出しで設定された値、または PYTHONHOME 環境変数の値を返します。が設定されます。
スレッドの状態とグローバルインタープリターロック
Pythonインタープリターは完全にスレッドセーフではありません。 マルチスレッドのPythonプログラムをサポートするために、グローバルインタープリターロックまたは GIL と呼ばれるグローバルロックがあります。これは、Pythonオブジェクトに安全にアクセスする前に、現在のスレッドによって保持される必要があります。 。 ロックがないと、最も単純な操作でもマルチスレッドプログラムで問題が発生する可能性があります。たとえば、2つのスレッドが同じオブジェクトの参照カウントを同時にインクリメントすると、参照カウントが2回ではなく1回だけインクリメントされる可能性があります。
したがって、 GIL を取得したスレッドのみがPythonオブジェクトを操作したり、Python / CAPI関数を呼び出したりできるというルールが存在します。 実行の同時実行性をエミュレートするために、インタープリターは定期的にスレッドの切り替えを試みます( sys.setswitchinterval()を参照)。 ロックは、ファイルの読み取りや書き込みなどのI / O操作をブロックする可能性がある場合にも解放されるため、その間に他のPythonスレッドを実行できます。
Pythonインタープリターは、 PyThreadState と呼ばれるデータ構造内にスレッド固有の簿記情報を保持します。 現在の PyThreadState を指すグローバル変数も1つあります。これは、 PyThreadState_Get()を使用して取得できます。
拡張コードからGILを解放する
GIL を操作するほとんどの拡張コードは、次の単純な構造を持っています。
Save the thread state in a local variable.
Release the global interpreter lock.
... Do some blocking I/O operation ...
Reacquire the global interpreter lock.
Restore the thread state from the local variable.
これは非常に一般的であるため、単純化するために1対のマクロが存在します。
Py_BEGIN_ALLOW_THREADS
... Do some blocking I/O operation ...
Py_END_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS マクロは、新しいブロックを開き、非表示のローカル変数を宣言します。 Py_END_ALLOW_THREADS マクロはブロックを閉じます。
上記のブロックは、次のコードに展開されます。
PyThreadState *_save;
_save = PyEval_SaveThread();
... Do some blocking I/O operation ...
PyEval_RestoreThread(_save);
これらの関数のしくみは次のとおりです。グローバルインタープリターロックは、現在のスレッド状態へのポインターを保護するために使用されます。 ロックを解放してスレッド状態を保存する場合、ロックが解放される前に現在のスレッド状態ポインターを取得する必要があります(別のスレッドがすぐにロックを取得し、独自のスレッド状態をグローバル変数に格納できるため)。 逆に、ロックを取得してスレッド状態を復元する場合は、スレッド状態ポインタを格納する前にロックを取得する必要があります。
Python以外で作成されたスレッド
専用のPythonAPI( threading モジュールなど)を使用してスレッドを作成すると、スレッドの状態が自動的にスレッドに関連付けられるため、上記のコードは正しいものになります。 ただし、スレッドがCから作成される場合(たとえば、独自のスレッド管理を備えたサードパーティライブラリによって)、スレッドはGILを保持せず、スレッド状態構造もありません。
これらのスレッドからPythonコードを呼び出す必要がある場合(多くの場合、これは前述のサードパーティライブラリによって提供されるコールバックAPIの一部になります)、最初にスレッド状態データ構造を作成してこれらのスレッドをインタープリターに登録し、次にPython / C APIの使用を開始する前に、GILを実行し、最後にスレッド状態ポインターを格納します。 完了したら、スレッド状態ポインターをリセットし、GILを解放して、最後にスレッド状態データ構造を解放する必要があります。
PyGILState_Ensure()および PyGILState_Release()関数は、上記のすべてを自動的に実行します。 CスレッドからPythonを呼び出すための一般的なイディオムは次のとおりです。
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
/* Perform Python actions here. */
result = CallSomeFunction();
/* evaluate result or handle exception */
/* Release the thread. No Python API allowed beyond this point. */
PyGILState_Release(gstate);
PyGILState _ * 関数は、グローバルインタープリターが1つしかないことを前提としていることに注意してください( Py_Initialize()によって自動的に作成されます)。 Pythonは追加のインタープリターの作成をサポートしていますが( Py_NewInterpreter()を使用)、複数のインタープリターと PyGILState _ * APIの混合はサポートされていません。
fork()に関する注意
スレッドについて注意すべきもう1つの重要な点は、C fork()
呼び出しに直面したときのスレッドの動作です。 fork()
を使用するほとんどのシステムでは、プロセスがフォークした後、フォークを発行したスレッドのみが存在します。 これは、ロックの処理方法とCPythonのランタイムのすべての保存状態の両方に具体的な影響を及ぼします。
「現在の」スレッドのみが残るという事実は、他のスレッドによって保持されているロックが解放されることは決してないことを意味します。 Pythonは、フォークの前に内部で使用するロックを取得し、後で解放することで、 os.fork()のこれを解決します。 さらに、子のロックオブジェクトをリセットします。 Pythonを拡張または埋め込む場合、フォークの前に取得するか、フォークの後にリセットする必要がある追加の(Python以外の)ロックをPythonに通知する方法はありません。 同じことを実現するには、pthread_atfork()
などのOS機能を使用する必要があります。 さらに、Pythonを拡張または埋め込む場合、 os.fork()を介さずにfork()
を直接呼び出す(およびPythonに戻るか呼び出す)と、Pythonの内部ロックの1つによってデッドロックが発生する可能性があります。フォークの後で機能しなくなったスレッドによって保持されています。 PyOS_AfterFork_Child()は必要なロックをリセットしようとしますが、常にリセットできるとは限りません。
他のすべてのスレッドがなくなるという事実は、CPythonのランタイム状態を適切にクリーンアップする必要があることも意味します。これは os.fork()が行います。 これは、現在のインタープリターに属する他のすべての PyThreadState オブジェクトと他のすべての PyInterpreterState オブジェクトをファイナライズすることを意味します。 これと「メイン」インタープリターの特殊な性質により、fork()
は、CPythonグローバルランタイムが最初に初期化されたそのインタープリターの「メイン」スレッドでのみ呼び出す必要があります。 唯一の例外は、exec()
が直後に呼び出される場合です。
高レベルAPI
これらは、C拡張コードを作成するとき、またはPythonインタープリターを埋め込むときに最も一般的に使用されるタイプと関数です。
- type PyInterpreterState
このデータ構造は、多数の協調スレッドによって共有される状態を表します。 同じインタープリターに属するスレッドは、モジュール管理と他のいくつかの内部項目を共有します。 この構造にはパブリックメンバーはありません。
異なるインタプリタに属するスレッドは、使用可能なメモリ、開いているファイル記述子などのプロセス状態を除いて、最初は何も共有しません。 グローバルインタプリタロックは、どのインタプリタに属しているかに関係なく、すべてのスレッドで共有されます。
- type PyThreadState
- このデータ構造は、単一スレッドの状態を表します。 唯一のパブリックデータメンバーは
interp
( PyInterpreterState * )であり、このスレッドのインタープリター状態を指します。
- void PyEval_InitThreads()
何もしない非推奨の関数。
Python 3.6以前では、この関数はGILが存在しない場合にGILを作成していました。
バージョン3.9で変更:関数は何もしないようになりました。
バージョン3.7で変更:この関数は Py_Initialize()によって呼び出されるようになったため、自分で呼び出す必要はありません。
バージョン3.2で変更:この関数は Py_Initialize()の前に呼び出すことができなくなりました。
- int PyEval_ThreadsInitialized()
PyEval_InitThreads()が呼び出された場合、ゼロ以外の値を返します。 この関数はGILを保持せずに呼び出すことができるため、シングルスレッドを実行しているときにロックAPIの呼び出しを回避するために使用できます。
バージョン3.7で変更: GIL は Py_Initialize()によって初期化されるようになりました。
- PyThreadState *PyEval_SaveThread()
- グローバルインタープリターロックを解放し(作成されている場合)、スレッドの状態を
NULL
にリセットして、前のスレッドの状態(NULL
ではない)を返します。 ロックが作成されている場合は、現在のスレッドがロックを取得している必要があります。
- void PyEval_RestoreThread(PyThreadState *tstate)
グローバルインタプリタロック(作成されている場合)を取得し、スレッドの状態を tstate に設定します。
NULL
であってはなりません。 ロックが作成されている場合は、現在のスレッドがロックを取得していない必要があります。取得していないと、デッドロックが発生します。ノート
ランタイムが終了しているときにスレッドからこの関数を呼び出すと、スレッドがPythonによって作成されていない場合でも、スレッドが終了します。
_Py_IsFinalizing()
または sys.is_finalizing()を使用して、この関数を呼び出す前にインタープリターがファイナライズ中であるかどうかを確認して、不要な終了を回避できます。
- PyThreadState *PyThreadState_Get()
- 現在のスレッドの状態を返します。 グローバルインタプリタロックを保持する必要があります。 現在のスレッドの状態が
NULL
の場合、致命的なエラーが発生します(したがって、呼び出し元はNULL
をチェックする必要がありません)。
- PyThreadState *PyThreadState_Swap(PyThreadState *tstate)
- 現在のスレッド状態を、引数 tstate で指定されたスレッド状態と交換します。これは
NULL
の場合があります。 グローバルインタプリタロックを保持する必要があり、解放されません。
次の関数はスレッドローカルストレージを使用し、サブインタープリターと互換性がありません。
- PyGILState_STATE PyGILState_Ensure()
Pythonの現在の状態やグローバルインタープリターロックに関係なく、現在のスレッドがPython CAPIを呼び出す準備ができていることを確認します。 これは、各呼び出しが PyGILState_Release()の呼び出しと一致する限り、スレッドによって必要な回数だけ呼び出される可能性があります。 一般に、 PyGILState_Ensure()と PyGILState_Release()の呼び出しの間では、Release()の前にスレッドの状態が以前の状態に復元されている限り、他のスレッド関連のAPIを使用できます。 たとえば、 Py_BEGIN_ALLOW_THREADS および Py_END_ALLOW_THREADS マクロの通常の使用法は許容されます。
戻り値は、 PyGILState_Ensure()が呼び出されたときのスレッド状態に対する不透明な「ハンドル」であり、Pythonが同じ状態のままになるように PyGILState_Release()に渡す必要があります。 再帰呼び出しは許可されていますが、これらのハンドルは共有できません。 PyGILState_Ensure()への一意の呼び出しごとに、 PyGILState_Release()への呼び出しのハンドルを保存する必要があります。
関数が戻ると、現在のスレッドはGILを保持し、任意のPythonコードを呼び出すことができます。 失敗は致命的なエラーです。
ノート
ランタイムが終了しているときにスレッドからこの関数を呼び出すと、スレッドがPythonによって作成されていない場合でも、スレッドが終了します。
_Py_IsFinalizing()
または sys.is_finalizing()を使用して、この関数を呼び出す前にインタープリターがファイナライズ中であるかどうかを確認して、不要な終了を回避できます。
- void PyGILState_Release(PyGILState_STATE)
以前に取得したリソースを解放します。 この呼び出しの後、Pythonの状態は、対応する PyGILState_Ensure()呼び出しの前と同じになります(ただし、通常、この状態は呼び出し元に認識されないため、GILState APIが使用されます)。
PyGILState_Ensure()へのすべての呼び出しは、同じスレッドでの PyGILState_Release()への呼び出しと一致する必要があります。
- PyThreadState *PyGILState_GetThisThreadState()
- このスレッドの現在のスレッド状態を取得します。 現在のスレッドでGILStateAPIが使用されていない場合、
NULL
を返す場合があります。 メインスレッドで自動スレッド状態の呼び出しが行われていなくても、メインスレッドには常にそのようなスレッド状態があることに注意してください。 これは主にヘルパー/診断機能です。
- int PyGILState_Check()
現在のスレッドがGILを保持している場合は
1
を返し、そうでない場合は0
を返します。 この関数は、いつでも任意のスレッドから呼び出すことができます。 Pythonスレッドの状態が初期化され、現在GILを保持している場合にのみ、1
が返されます。 これは主にヘルパー/診断機能です。 たとえば、コールバックコンテキストやメモリ割り当て関数で、GILがロックされていることがわかっていると、呼び出し元が機密性の高いアクションを実行したり、異なる動作をしたりできる場合に役立ちます。バージョン3.4の新機能。
次のマクロは通常、末尾にセミコロンを付けずに使用されます。 Pythonソースディストリビューションでの使用例を探してください。
- Py_BEGIN_ALLOW_THREADS
- このマクロは
{ PyThreadState *_save; _save = PyEval_SaveThread();
に展開されます。 開始中括弧が含まれていることに注意してください。 次の Py_END_ALLOW_THREADS マクロと一致する必要があります。 このマクロの詳細については、上記を参照してください。
- Py_END_ALLOW_THREADS
- このマクロは
PyEval_RestoreThread(_save); }
に展開されます。 閉じ中括弧が含まれていることに注意してください。 以前の Py_BEGIN_ALLOW_THREADS マクロと一致する必要があります。 このマクロの詳細については、上記を参照してください。
- Py_BLOCK_THREADS
- このマクロは
PyEval_RestoreThread(_save);
に展開されます。これは Py_END_ALLOW_THREADS と同等です。
- Py_UNBLOCK_THREADS
- このマクロは
_save = PyEval_SaveThread();
に展開されます。これは、開始中括弧と変数宣言がない Py_BEGIN_ALLOW_THREADS と同等です。
低レベルAPI
次のすべての関数は、 Py_Initialize()の後に呼び出す必要があります。
バージョン3.7で変更: Py_Initialize()が GIL を初期化するようになりました。
- PyInterpreterState *PyInterpreterState_New()
- 新しいインタプリタ状態オブジェクトを作成します。 グローバルインタプリタロックを保持する必要はありませんが、この関数の呼び出しをシリアル化する必要がある場合は保持できます。
- void PyInterpreterState_Clear(PyInterpreterState *interp)
- インタプリタ状態オブジェクトのすべての情報をリセットします。 グローバルインタプリタロックを保持する必要があります。
- void PyInterpreterState_Delete(PyInterpreterState *interp)
- インタプリタ状態オブジェクトを破棄します。 グローバルインタプリタロックを保持する必要はありません。 インタプリタの状態は、 PyInterpreterState_Clear()への以前の呼び出しでリセットされている必要があります。
- PyThreadState *PyThreadState_New(PyInterpreterState *interp)
- 指定されたインタプリタオブジェクトに属する新しいスレッド状態オブジェクトを作成します。 グローバルインタプリタロックを保持する必要はありませんが、この関数の呼び出しをシリアル化する必要がある場合は保持できます。
- void PyThreadState_Clear(PyThreadState *tstate)
スレッド状態オブジェクトのすべての情報をリセットします。 グローバルインタプリタロックを保持する必要があります。
バージョン3.9で変更:この関数は
PyThreadState.on_delete
コールバックを呼び出すようになりました。 以前は、 PyThreadState_Delete()で発生していました。
- void PyThreadState_Delete(PyThreadState *tstate)
- スレッド状態オブジェクトを破棄します。 グローバルインタプリタロックを保持する必要はありません。 スレッドの状態は、 PyThreadState_Clear()への前回の呼び出しでリセットされている必要があります。
- void PyThreadState_DeleteCurrent(void)
- 現在のスレッド状態を破棄し、グローバルインタープリターロックを解放します。 PyThreadState_Delete()と同様に、グローバルインタープリターロックを保持する必要はありません。 スレッドの状態は、 PyThreadState_Clear()への前回の呼び出しでリセットされている必要があります。
- PyFrameObject *PyThreadState_GetFrame(PyThreadState *tstate)
Pythonスレッド状態 tstate の現在のフレームを取得します。
強力な参照を返します。 現在実行中のフレームがない場合は、
NULL
を返します。PyEval_GetFrame()も参照してください。
tstate は
NULL
であってはなりません。バージョン3.9の新機能。
- uint64_t PyThreadState_GetID(PyThreadState *tstate)
Pythonスレッド状態 tstate の一意のスレッド状態識別子を取得します。
tstate は
NULL
であってはなりません。バージョン3.9の新機能。
- PyInterpreterState *PyThreadState_GetInterpreter(PyThreadState *tstate)
Pythonスレッド状態 tstate のインタープリターを取得します。
tstate は
NULL
であってはなりません。バージョン3.9の新機能。
- PyInterpreterState *PyInterpreterState_Get(void)
現在のインタプリタを取得します。
現在のPythonスレッドの状態がない場合、または現在のインタープリターがない場合は、致命的なエラーを発行します。 NULLを返すことはできません。
発信者はGILを保持する必要があります。
バージョン3.9の新機能。
- int64_t PyInterpreterState_GetID(PyInterpreterState *interp)
通訳者の一意のIDを返します。 エラーが発生した場合は、
-1
が返され、エラーが設定されます。発信者はGILを保持する必要があります。
バージョン3.7の新機能。
- PyObject *PyInterpreterState_GetDict(PyInterpreterState *interp)
インタプリタ固有のデータが格納されている可能性のある辞書を返します。 この関数が
NULL
を返す場合、例外は発生しておらず、呼び出し元はインタプリタ固有のdictが使用できないと想定する必要があります。これは、 PyModule_GetState()の代わりにはなりません。拡張機能は、インタープリター固有の状態情報を格納するために使用する必要があります。
バージョン3.8の新機能。
- typedef PyObject *(*_PyFrameEvalFunction)(PyThreadState *tstate, PyFrameObject *frame, int throwflag)
フレーム評価関数のタイプ。
throwflag パラメーターは、ジェネレーターの
throw()
メソッドによって使用されます。ゼロ以外の場合は、現在の例外を処理します。バージョン3.9で変更:この関数は tstate パラメーターを受け取るようになりました。
- _PyFrameEvalFunction _PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp)
フレーム評価関数を取得します。
PEP 523 「CPythonへのフレーム評価APIの追加」を参照してください。
バージョン3.9の新機能。
- void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame)
フレーム評価関数を設定します。
PEP 523 「CPythonへのフレーム評価APIの追加」を参照してください。
バージョン3.9の新機能。
- PyObject *PyThreadState_GetDict()
- 拡張機能がスレッド固有の状態情報を格納できる辞書を返します。 各拡張機能は、ディクショナリに状態を格納するために使用する一意のキーを使用する必要があります。 現在のスレッド状態が利用できない場合は、この関数を呼び出してもかまいません。 この関数が
NULL
を返す場合、例外は発生しておらず、呼び出し元は現在のスレッド状態が利用できないと想定する必要があります。
- int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
スレッドで非同期的に例外を発生させます。 id 引数は、ターゲットスレッドのスレッドIDです。 exc は、発生する例外オブジェクトです。 この関数は、 exc への参照を盗みません。 素朴な誤用を防ぐために、これを呼び出すために独自のC拡張機能を作成する必要があります。 GILを保持したまま呼び出す必要があります。 変更されたスレッド状態の数を返します。 これは通常1ですが、スレッドIDが見つからない場合は0になります。 exc が
NULL
の場合、スレッドの保留中の例外(存在する場合)はクリアされます。 これは例外を引き起こしません。バージョン3.7で変更: id パラメーターのタイプが long から unsigned long に変更されました。
- void PyEval_AcquireThread(PyThreadState *tstate)
グローバルインタプリタロックを取得し、現在のスレッド状態を tstate に設定します。
NULL
であってはなりません。 ロックは以前に作成されている必要があります。 このスレッドがすでにロックを持っている場合、デッドロックが発生します。ノート
ランタイムが終了しているときにスレッドからこの関数を呼び出すと、スレッドがPythonによって作成されていない場合でも、スレッドが終了します。
_Py_IsFinalizing()
または sys.is_finalizing()を使用して、この関数を呼び出す前にインタープリターがファイナライズ中であるかどうかを確認して、不要な終了を回避できます。バージョン3.8で変更: PyEval_RestoreThread()、 Py_END_ALLOW_THREADS()、および PyGILState_Ensure()と一致するように更新され、終了しますインタプリタのファイナライズ中に呼び出された場合は、現在のスレッド。
PyEval_RestoreThread()は、(スレッドが初期化されていない場合でも)常に使用可能な高レベルの関数です。
- void PyEval_ReleaseThread(PyThreadState *tstate)
現在のスレッド状態を
NULL
にリセットし、グローバルインタープリターロックを解除します。 ロックは以前に作成されている必要があり、現在のスレッドによって保持されている必要があります。 tstate 引数は、NULL
であってはならず、現在のスレッド状態を表していることを確認するためにのみ使用されます。そうでない場合は、致命的なエラーが報告されます。PyEval_SaveThread()は、(スレッドが初期化されていない場合でも)常に使用可能な高レベルの関数です。
- void PyEval_AcquireLock()
グローバルインタプリタロックを取得します。 ロックは以前に作成されている必要があります。 このスレッドがすでにロックを持っている場合、デッドロックが発生します。
バージョン3.2以降非推奨:この関数は現在のスレッド状態を更新しません。 代わりに、 PyEval_RestoreThread()または PyEval_AcquireThread()を使用してください。
ノート
ランタイムが終了しているときにスレッドからこの関数を呼び出すと、スレッドがPythonによって作成されていない場合でも、スレッドが終了します。
_Py_IsFinalizing()
または sys.is_finalizing()を使用して、この関数を呼び出す前にインタープリターがファイナライズ中であるかどうかを確認して、不要な終了を回避できます。バージョン3.8で変更: PyEval_RestoreThread()、 Py_END_ALLOW_THREADS()、および PyGILState_Ensure()と一致するように更新され、終了しますインタプリタのファイナライズ中に呼び出された場合は、現在のスレッド。
- void PyEval_ReleaseLock()
グローバルインタプリタロックを解除します。 ロックは以前に作成されている必要があります。
バージョン3.2以降非推奨:この関数は現在のスレッド状態を更新しません。 代わりに、 PyEval_SaveThread()または PyEval_ReleaseThread()を使用してください。
サブインタプリタのサポート
ほとんどの用途では、単一のPythonインタープリターのみを埋め込みますが、同じプロセスで、場合によっては同じスレッドでさえ、複数の独立したインタープリターを作成する必要がある場合があります。 サブインタープリターはあなたがそれをすることを可能にします。
「メイン」インタプリタは、ランタイムの初期化時に作成される最初のインタプリタです。 これは通常、プロセス内の唯一のPythonインタープリターです。 サブインタプリタとは異なり、メインインタプリタには、信号処理などの独自のプロセスグローバルな責任があります。 また、実行時の初期化中の実行も担当し、通常、実行時のファイナライズ中のアクティブなインタープリターです。 PyInterpreterState_Main()関数は、その状態へのポインターを返します。
PyThreadState_Swap()関数を使用して、サブインタープリターを切り替えることができます。 次の関数を使用して、それらを作成および破棄できます。
- PyThreadState *Py_NewInterpreter()
新しいサブインタープリターを作成します。 これは、Pythonコードを実行するための(ほぼ)完全に独立した環境です。 特に、新しいインタプリタには、基本モジュール builtins 、 __ main __ 、 sys を含む、インポートされたすべてのモジュールの個別の独立したバージョンがあります。 ロードされたモジュールのテーブル(
sys.modules
)とモジュール検索パス(sys.path
)も分離されています。 新しい環境にはsys.argv
変数がありません。 新しい標準I / Oストリームファイルオブジェクトsys.stdin
、sys.stdout
、およびsys.stderr
があります(ただし、これらは同じ基になるファイル記述子を参照します)。戻り値は、新しいサブインタープリターで作成された最初のスレッド状態を指します。 このスレッド状態は、現在のスレッド状態で作成されます。 実際のスレッドは作成されないことに注意してください。 以下のスレッド状態の説明を参照してください。 新しいインタプリタの作成に失敗した場合、
NULL
が返されます。 例外状態は現在のスレッド状態に格納され、現在のスレッド状態がない可能性があるため、例外は設定されません。 (他のすべてのPython / C API関数と同様に、グローバルインタープリターロックはこの関数を呼び出す前に保持する必要があり、戻ったときに保持されます。ただし、他のほとんどのPython / C API関数とは異なり、現在のスレッド状態がオンである必要はありません。エントリ。)拡張モジュールは、次のように(サブ)インタープリター間で共有されます。
マルチフェーズ初期化を使用するモジュールの場合、例: PyModule_FromDefAndSpec()、インタプリタごとに個別のモジュールオブジェクトが作成され、初期化されます。 これらのモジュールオブジェクト間で共有されるのは、経営幹部レベルの静的変数とグローバル変数のみです。
単相初期化を使用するモジュールの場合、例: PyModule_Create()、特定の拡張機能が初めてインポートされると、通常どおり初期化され、そのモジュールの辞書の(浅い)コピーが削除されます。 同じ拡張機能が別の(サブ)インタープリターによってインポートされると、新しいモジュールが初期化され、このコピーの内容が入力されます。 拡張機能の
init
関数は呼び出されません。 したがって、モジュールのディクショナリ内のオブジェクトは、(サブ)インタプリタ間で共有されることになり、望ましくない動作を引き起こす可能性があります(以下のバグと警告を参照)。これは、 Py_FinalizeEx()および Py_Initialize()を呼び出してインタープリターが完全に再初期化された後に拡張機能がインポートされた場合とは異なることに注意してください。 その場合、拡張機能の
initmodule
関数がに再度呼び出されます。 マルチフェーズ初期化と同様に、これは、Cレベルの静的変数とグローバル変数のみがこれらのモジュール間で共有されることを意味します。
- void Py_EndInterpreter(PyThreadState *tstate)
- 指定されたスレッド状態で表される(サブ)インタープリターを破棄します。 指定されたスレッド状態は、現在のスレッド状態である必要があります。 以下のスレッド状態の説明を参照してください。 呼び出しが戻ると、現在のスレッドの状態は
NULL
です。 このインタプリタに関連付けられているすべてのスレッド状態が破棄されます。 (グローバルインタープリターロックは、この関数を呼び出す前に保持する必要があり、戻ったときにも保持されます。) Py_FinalizeEx()は、その時点で明示的に破棄されていないすべてのサブインタープリターを破棄します。
バグと警告
サブインタープリター(およびメインインタープリター)は同じプロセスの一部であるため、それらの間の分離は完全ではありません。たとえば、 os.close()のような低レベルのファイル操作を使用できます(偶然または悪意を持って)お互いの開いているファイルに影響を与えます。 拡張機能が(サブ)インタープリター間で共有される方法のため、一部の拡張機能は正しく機能しない場合があります。 これは、単相初期化または(静的)グローバル変数を使用する場合に特に発生する可能性があります。 あるサブインタープリターで作成されたオブジェクトを別の(サブ)インタープリターの名前空間に挿入することができます。 可能であれば、これは避ける必要があります。
サブインタープリター間でユーザー定義の関数、メソッド、インスタンス、またはクラスを共有しないように特別な注意を払う必要があります。そのようなオブジェクトによって実行されるインポート操作は、ロードされたモジュールの間違った(サブ)インタープリターのディクショナリに影響を与える可能性があるためです。 上記に到達できるオブジェクトを共有しないようにすることも同様に重要です。
また、この機能を PyGILState _ * APIと組み合わせるのは微妙であることに注意してください。これらのAPIは、Pythonスレッドの状態とOSレベルのスレッドの間の全単射を想定しているためです。 一致する PyGILState_Ensure()呼び出しと PyGILState_Release()呼び出しのペア間でサブインタープリターを切り替えないことを強くお勧めします。 さらに、これらのAPIを使用してPythonで作成されていないスレッドからPythonコードを呼び出すことができる拡張機能( ctypes など)は、サブインタープリターを使用すると壊れてしまう可能性があります。
非同期通知
メインのインタプリタスレッドに非同期通知を行うメカニズムが提供されています。 これらの通知は、関数ポインタとvoidポインタ引数の形式を取ります。
- int Py_AddPendingCall(int (*func)(void*), void *arg)
メインのインタプリタスレッドから呼び出される関数をスケジュールします。 成功すると、
0
が返され、 func がメインスレッドで呼び出されるためにキューに入れられます。 失敗すると、例外を設定せずに-1
が返されます。正常にキューに入れられると、 func は、引数 arg を使用してメインインタープリタースレッドから最終的に呼び出されます。 通常実行されているPythonコードに関しては非同期で呼び出されますが、次の両方の条件が満たされています。
バイトコード境界上。
メインスレッドがグローバルインタープリターロックを保持している(したがって、 func は完全なCAPIを使用できます)。
func は、成功した場合は
0
を返し、失敗した場合は例外セットを使用して-1
を返す必要があります。 func は、別の非同期通知を再帰的に実行するために中断されることはありませんが、グローバルインタープリターロックが解放された場合でも、スレッドを切り替えるために中断される可能性があります。この関数は、実行するために現在のスレッド状態を必要とせず、グローバルインタープリターロックも必要ありません。
サブインタープリターでこの関数を呼び出すには、呼び出し元がGILを保持している必要があります。 そうしないと、関数 func が間違ったインタープリターから呼び出されるようにスケジュールされる可能性があります。
警告
これは低レベルの関数であり、非常に特殊な場合にのみ役立ちます。 func ができるだけ早く呼び出されるという保証はありません。 メインスレッドがシステムコールの実行でビジー状態の場合、システムコールが戻る前に func は呼び出されません。 この関数は通常、任意のCスレッドからPythonコードを呼び出すのに適切ではありません。 代わりに、 PyGILState API を使用してください。
バージョン3.9で変更:この関数がサブインタープリターで呼び出された場合、関数 func は、メインインタープリターから呼び出されるのではなく、サブインタープリターから呼び出されるようにスケジュールされます。 各サブインタープリターには、スケジュールされた通話の独自のリストがあります。
バージョン3.1の新機能。
プロファイリングとトレース
Pythonインタープリターは、プロファイリングおよび実行トレース機能をアタッチするための低レベルのサポートを提供します。 これらは、プロファイリング、デバッグ、およびカバレッジ分析ツールに使用されます。
このCインターフェースにより、プロファイリングまたはトレースコードは、Pythonレベルの呼び出し可能オブジェクトを介した呼び出しのオーバーヘッドを回避し、代わりに直接C関数呼び出しを行うことができます。 施設の本質的な属性は変更されていません。 このインターフェースでは、トレース関数をスレッドごとにインストールできます。トレース関数に報告される基本的なイベントは、以前のバージョンのPythonレベルのトレース関数に報告されたものと同じです。
- typedef int (*Py_tracefunc)(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg)
PyEval_SetProfile()および PyEval_SetTrace()を使用して登録されたトレース関数のタイプ。 最初のパラメータは、 obj として登録関数に渡されるオブジェクトです。 frame はイベントが関係するフレームオブジェクトであり、 what は定数の1つです[ X189X] 、
PyTrace_EXCEPTION
、PyTrace_LINE
、PyTrace_RETURN
、PyTrace_C_CALL
、PyTrace_C_EXCEPTION
、PyTrace_C_RETURN
、または[ X273X] 、および arg は、 what の値によって異なります。what の値
arg の意味
PyTrace_CALL
常に Py_None 。
PyTrace_EXCEPTION
sys.exc_info()によって返される例外情報。
PyTrace_LINE
常に Py_None 。
PyTrace_RETURN
呼び出し元に返される値、または例外が原因の場合は
NULL
。PyTrace_C_CALL
呼び出されている関数オブジェクト。
PyTrace_C_EXCEPTION
呼び出されている関数オブジェクト。
PyTrace_C_RETURN
呼び出されている関数オブジェクト。
PyTrace_OPCODE
常に Py_None 。
- int PyTrace_CALL
- 関数またはメソッドへの新しい呼び出し、またはジェネレーターへの新しいエントリが報告されているときの、 Py_tracefunc 関数に対する what パラメーターの値。 対応するフレームのPythonバイトコードへの制御転送がないため、ジェネレーター関数のイテレーターの作成は報告されないことに注意してください。
- int PyTrace_EXCEPTION
- 例外が発生したときの Py_tracefunc 関数に対する what パラメーターの値。 コールバック関数は、バイトコードが処理された後、実行中のフレーム内で例外が設定されると、 what に対してこの値で呼び出されます。 この効果は、例外の伝播によってPythonスタックがアンワインドされるため、例外が伝播するときに各フレームに戻るときにコールバックが呼び出されることです。 トレース関数のみがこれらのイベントを受け取ります。 プロファイラーには必要ありません。
- int PyTrace_LINE
- 行番号イベントが報告されているときに、 what パラメーターとして Py_tracefunc 関数(プロファイリング関数ではない)に渡される値。 フレームの
f_trace_lines
を 0 に設定すると、そのフレームで無効にできます。
- int PyTrace_RETURN
- Py_tracefunc への what パラメーターの値は、呼び出しが返されようとしているときに機能します。
- int PyTrace_C_CALL
- C関数が呼び出されようとしているときの Py_tracefunc 関数の what パラメーターの値。
- int PyTrace_C_EXCEPTION
- C関数で例外が発生した場合の Py_tracefunc 関数の what パラメーターの値。
- int PyTrace_C_RETURN
- C関数が戻ったときの Py_tracefunc 関数の what パラメーターの値。
- int PyTrace_OPCODE
- 新しいオペコードが実行されようとしているときの Py_tracefunc 関数(プロファイリング関数ではない)に対する what パラメーターの値。 このイベントはデフォルトでは発行されません。フレームで
f_trace_opcodes
を 1 に設定して、明示的に要求する必要があります。
- void PyEval_SetProfile(Py_tracefunc func, PyObject *obj)
プロファイラー機能を func に設定します。 obj パラメーターは、最初のパラメーターとして関数に渡され、任意のPythonオブジェクトまたは
NULL
にすることができます。 プロファイル関数が状態を維持する必要がある場合、スレッドごとに obj に異なる値を使用すると、それを格納するための便利でスレッドセーフな場所が提供されます。 プロファイル関数は、PyTrace_LINE
PyTrace_OPCODE
およびPyTrace_EXCEPTION
を除くすべての監視対象イベントに対して呼び出されます。発信者は GIL を保持している必要があります。
- void PyEval_SetTrace(Py_tracefunc func, PyObject *obj)
トレース機能を func に設定してください。 これは PyEval_SetProfile()に似ていますが、トレース関数は行番号イベントとオペコードごとのイベントを受信しますが、呼び出されているC関数オブジェクトに関連するイベントは受信しません。 PyEval_SetTrace()を使用して登録されたトレース関数は、 what パラメーターの値として
PyTrace_C_CALL
、PyTrace_C_EXCEPTION
、またはPyTrace_C_RETURN
を受け取りません。 。発信者は GIL を保持している必要があります。
高度なデバッガーのサポート
これらの関数は、高度なデバッグツールでのみ使用することを目的としています。
- PyInterpreterState *PyInterpreterState_Head()
- そのようなすべてのオブジェクトのリストの先頭にあるインタープリター状態オブジェクトを返します。
- PyInterpreterState *PyInterpreterState_Main()
- メインのインタプリタ状態オブジェクトを返します。
- PyInterpreterState *PyInterpreterState_Next(PyInterpreterState *interp)
- そのようなすべてのオブジェクトのリストから、 interp の後に次のインタープリター状態オブジェクトを返します。
- PyThreadState *PyInterpreterState_ThreadHead(PyInterpreterState *interp)
- インタプリタ interp に関連付けられたスレッドのリストの最初の PyThreadState オブジェクトへのポインタを返します。
- PyThreadState *PyThreadState_Next(PyThreadState *tstate)
- 同じ PyInterpreterState オブジェクトに属するそのようなすべてのオブジェクトのリストから、 tstate の次のスレッド状態オブジェクトを返します。
スレッドローカルストレージのサポート
Pythonインタープリターは、PythonレベルのスレッドローカルストレージAPI( threading.local )をサポートするために、基盤となるネイティブTLS実装をラップするスレッドローカルストレージ(TLS)の低レベルのサポートを提供します。 CPython CレベルのAPIは、pthreadやWindowsで提供されているものと似ています。スレッドキーと関数を使用して、スレッドごとに void * 値を関連付けます。
GILは、これらの関数を呼び出すときにを保持する必要はありません。 それらは独自のロックを提供します。
Python.h
にはTLSAPIの宣言が含まれていないことに注意してください。スレッドローカルストレージを使用するには、pythread.h
を含める必要があります。
ノート
これらのAPI関数はいずれも、 void * 値に代わってメモリ管理を処理しません。 自分で割り当てたり、割り当てを解除したりする必要があります。 void * の値がたまたま PyObject * の場合、これらの関数はそれらに対してrefcount操作も実行しません。
スレッド固有ストレージ(TSS)API
TSS APIは、CPythonインタープリター内での既存のTLSAPIの使用に取って代わるために導入されました。 このAPIは、スレッドキーを表すために int の代わりに新しいタイプ Py_tss_t を使用します。
バージョン3.7の新機能。
- type Py_tss_t
このデータ構造はスレッドキーの状態を表し、その定義は基になるTLS実装に依存する可能性があり、キーの初期化状態を表す内部フィールドがあります。 この構造にはパブリックメンバーはありません。
Py_LIMITED_API が定義されていない場合、 Py_tss_NEEDS_INIT によるこのタイプの静的割り当てが許可されます。
- Py_tss_NEEDS_INIT
- このマクロは、 Py_tss_t 変数の初期化子に展開されます。 このマクロは Py_LIMITED_API では定義されないことに注意してください。
動的割り当て
Py_tss_t の動的割り当て。 Py_LIMITED_API でビルドされた拡張モジュールで必要です。このタイプの静的割り当ては、ビルド時に実装が不透明であるため不可能です。
- Py_tss_t *PyThread_tss_alloc()
- Py_tss_NEEDS_INIT で初期化された値、または動的割り当てが失敗した場合は
NULL
で初期化された値と同じ状態の値を返します。
- void PyThread_tss_free(Py_tss_t *key)
最初に PyThread_tss_delete()を呼び出した後、 PyThread_tss_alloc()によって割り当てられた特定のキーを解放して、関連付けられたスレッドローカルが割り当て解除されていることを確認します。 key 引数が NULL の場合、これはノーオペレーションです。
ノート
解放されたキーはダングリングポインタになります。キーを NULL にリセットする必要があります。
メソッド
これらの関数のパラメーターキーはNULL
であってはなりません。 さらに、 PyThread_tss_set()および PyThread_tss_get()の動作は、指定された Py_tss_t が PyThread_tss_create()によって初期化されていない場合は未定義です。 。
- int PyThread_tss_is_created(Py_tss_t *key)
- 指定された Py_tss_t が PyThread_tss_create()によって初期化されている場合は、ゼロ以外の値を返します。
- int PyThread_tss_create(Py_tss_t *key)
- TSSキーの初期化が成功すると、ゼロ値を返します。 key 引数が指す値が、 Py_tss_NEEDS_INIT によって初期化されていない場合、動作は未定義です。 この関数は、同じキーで繰り返し呼び出すことができます。すでに初期化されているキーで呼び出すと、何も実行されず、すぐに成功が返されます。
- void PyThread_tss_delete(Py_tss_t *key)
- TSSキーを破棄して、すべてのスレッドでキーに関連付けられている値を忘れ、キーの初期化状態を未初期化に変更します。 破棄されたキーは、 PyThread_tss_create()によって再度初期化できます。 この関数は、同じキーで繰り返し呼び出すことができます。すでに破棄されているキーで呼び出すことはできません。
- int PyThread_tss_set(Py_tss_t *key, void *value)
- ゼロ値を返し、 void * 値が現在のスレッドのTSSキーに正常に関連付けられたことを示します。 各スレッドには、 void * 値へのキーの個別のマッピングがあります。
- void *PyThread_tss_get(Py_tss_t *key)
- 現在のスレッドのTSSキーに関連付けられている void * 値を返します。 現在のスレッドのキーに値が関連付けられていない場合、これは
NULL
を返します。
スレッドローカルストレージ(TLS)API
バージョン3.7以降非推奨:このAPIは、スレッド固有記憶(TSS)API に置き換えられました。
ノート
このバージョンのAPIは、int
に安全にキャストできない方法でネイティブTLSキーが定義されているプラットフォームをサポートしていません。 そのようなプラットフォームでは、 PyThread_create_key()はすぐに失敗ステータスで戻り、他のTLS関数はすべてそのようなプラットフォームでは動作しません。
上記の互換性の問題のため、このバージョンのAPIを新しいコードで使用しないでください。
- int PyThread_create_key()
- void PyThread_delete_key(int key)
- int PyThread_set_key_value(int key, void *value)
- void *PyThread_get_key_value(int key)
- void PyThread_delete_key_value(int key)
- void PyThread_ReInitTLS()