初始化、最終化和執行緒¶
有關如何在初始化之前配置直譯器的詳細資訊,請參閱Python 初始化配置。
Python 初始化之前¶
在嵌入 Python 的應用程式中,必須在呼叫任何其他 Python/C API 函式之前呼叫Py_Initialize()
函式;除了少數函式和全域性配置變數。
以下函式可以在 Python 初始化之前安全呼叫
初始化直譯器的函式
配置函式
資訊函式
實用程式
在Python 初始化配置中介紹的狀態報告和實用程式函式
記憶體分配器
同步
注意
儘管它們與上面列出的某些函式明顯相似,但在直譯器初始化之前,不應呼叫以下函式:Py_EncodeLocale()
, Py_GetPath()
, Py_GetPrefix()
, Py_GetExecPrefix()
, Py_GetProgramFullPath()
, Py_GetPythonHome()
, Py_GetProgramName()
, PyEval_InitThreads()
, 和 Py_RunMain()
。
全域性配置變數¶
Python 具有用於全域性配置的變數,以控制不同的功能和選項。預設情況下,這些標誌由命令列選項控制。
當一個標誌被一個選項設定時,該標誌的值是該選項被設定的次數。 例如,-b
將Py_BytesWarningFlag
設定為 1,-bb
將Py_BytesWarningFlag
設定為 2。
-
int Py_BytesWarningFlag¶
保留此 API 以實現向後相容性:應使用設定
PyConfig.bytes_warning
,請參閱Python 初始化配置。當比較
bytes
或bytearray
與str
或bytes
與int
時發出警告。如果大於或等於2
,則發出錯誤。由
-b
選項設定。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_DebugFlag¶
保留此 API 以實現向後相容性:應使用設定
PyConfig.parser_debug
,請參閱Python 初始化配置。開啟解析器除錯輸出(僅供專家使用,取決於編譯選項)。
由
-d
選項和PYTHONDEBUG
環境變數設定。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_DontWriteBytecodeFlag¶
保留此 API 以實現向後相容性:應使用設定
PyConfig.write_bytecode
,請參閱Python 初始化配置。如果設定為非零值,Python 將不會嘗試在匯入源模組時寫入
.pyc
檔案。由
-B
選項和PYTHONDONTWRITEBYTECODE
環境變數設定。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_FrozenFlag¶
保留此 API 以實現向後相容性:應使用設定
PyConfig.pathconfig_warnings
,請參閱Python 初始化配置。在
Py_GetPath()
中計算模組搜尋路徑時,禁止顯示錯誤訊息。由
_freeze_module
和frozenmain
程式使用的私有標誌。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_HashRandomizationFlag¶
保留此 API 以實現向後相容性:應使用設定
PyConfig.hash_seed
和PyConfig.use_hash_seed
,請參閱Python 初始化配置。如果
PYTHONHASHSEED
環境變數設定為非空字串,則設定為1
。如果該標誌非零,則讀取
PYTHONHASHSEED
環境變數以初始化秘密雜湊種子。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_IgnoreEnvironmentFlag¶
此 API 保留是為了向後相容:應使用設定
PyConfig.use_environment
,請參閱 Python 初始化配置。忽略所有
PYTHON*
環境變數,例如PYTHONPATH
和PYTHONHOME
,這些變數可能會被設定。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_InspectFlag¶
此 API 保留是為了向後相容:應使用設定
PyConfig.inspect
,請參閱 Python 初始化配置。當指令碼作為第一個引數傳遞,或者使用了
-c
選項時,即使sys.stdin
看起來不是終端,也會在執行指令碼或命令後進入互動模式。由
-i
選項和PYTHONINSPECT
環境變數設定。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_InteractiveFlag¶
此 API 保留是為了向後相容:應使用設定
PyConfig.interactive
,請參閱 Python 初始化配置。由
-i
選項設定。自 3.12 版本起已棄用。
-
int Py_IsolatedFlag¶
此 API 保留是為了向後相容:應使用設定
PyConfig.isolated
,請參閱 Python 初始化配置。在隔離模式下執行 Python。在隔離模式下,
sys.path
既不包含指令碼的目錄,也不包含使用者的 site-packages 目錄。由
-I
選項設定。在 3.4 版本中新增。
自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_LegacyWindowsFSEncodingFlag¶
此 API 保留是為了向後相容:應使用設定
PyPreConfig.legacy_windows_fs_encoding
,請參閱 Python 初始化配置。如果該標誌為非零值,則使用
mbcs
編碼和replace
錯誤處理程式,而不是 UTF-8 編碼和surrogatepass
錯誤處理程式,用於 檔案系統編碼和錯誤處理程式。如果
PYTHONLEGACYWINDOWSFSENCODING
環境變數設定為非空字串,則設定為1
。有關更多詳細資訊,請參閱 PEP 529。
可用性:Windows。
自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_LegacyWindowsStdioFlag¶
此 API 保留是為了向後相容:應使用設定
PyConfig.legacy_windows_stdio
,請參閱 Python 初始化配置。如果該標誌為非零值,則對
sys
標準流使用io.FileIO
而不是io._WindowsConsoleIO
。如果
PYTHONLEGACYWINDOWSSTDIO
環境變數設定為非空字串,則設定為1
。有關更多詳細資訊,請參閱 PEP 528。
可用性:Windows。
自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_NoSiteFlag¶
此 API 保留是為了向後相容:應使用設定
PyConfig.site_import
,請參閱 Python 初始化配置。停用模組
site
的匯入以及由此引起的對sys.path
的站點相關操作。如果稍後顯式匯入site
,也停用這些操作(如果要觸發這些操作,請呼叫site.main()
)。由
-S
選項設定。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_NoUserSiteDirectory¶
此 API 保留是為了向後相容:應使用設定
PyConfig.user_site_directory
,請參閱 Python 初始化配置。不要將
使用者 site-packages 目錄
新增到sys.path
。由
-s
和-I
選項以及PYTHONNOUSERSITE
環境變數設定。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_OptimizeFlag¶
此 API 保留是為了向後相容:應使用設定
PyConfig.optimization_level
,請參閱 Python 初始化配置。由
-O
選項和PYTHONOPTIMIZE
環境變數設定。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_QuietFlag¶
此 API 保留是為了向後相容:應使用設定
PyConfig.quiet
,請參閱 Python 初始化配置。即使在互動模式下也不顯示版權和版本資訊。
由
-q
選項設定。在 3.2 版本中新增。
自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_UnbufferedStdioFlag¶
此 API 保留用於向後相容:應使用
PyConfig.buffered_stdio
來代替,請參閱 Python 初始化配置。強制 stdout 和 stderr 流不使用緩衝。
由
-u
選項和PYTHONUNBUFFERED
環境變數設定。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
-
int Py_VerboseFlag¶
此 API 保留用於向後相容:應使用
PyConfig.verbose
來代替,請參閱 Python 初始化配置。每次初始化模組時都列印一條訊息,顯示模組的載入位置(檔名或內建模組)。如果大於或等於
2
,則為搜尋模組時檢查的每個檔案列印一條訊息。還提供有關退出時模組清理的資訊。由
-v
選項和PYTHONVERBOSE
環境變數設定。自 3.12 版本起已棄用,將在 3.14 版本中刪除。
初始化和終止直譯器¶
-
void Py_Initialize()¶
- 屬於 穩定 ABI 的一部分。
初始化 Python 直譯器。在嵌入 Python 的應用程式中,應在呼叫任何其他 Python/C API 函式之前呼叫此函式;有關少數例外情況,請參閱 Python 初始化之前。
這將初始化已載入模組的表(
sys.modules
),並建立基本模組builtins
、__main__
和sys
。它還會初始化模組搜尋路徑(sys.path
)。它不會設定sys.argv
;請使用 Python 初始化配置 API。如果第二次呼叫此函式(在未先呼叫Py_FinalizeEx()
的情況下),則此函式不執行任何操作。沒有返回值;如果初始化失敗,則會發生致命錯誤。使用
Py_InitializeFromConfig()
自定義 Python 初始化配置。注意
在 Windows 上,將控制檯模式從
O_TEXT
更改為O_BINARY
,這也將影響使用 C 執行時控制檯的非 Python 用途。
-
void Py_InitializeEx(int initsigs)¶
- 屬於 穩定 ABI 的一部分。
如果 initsigs 為
1
,則此函式的工作方式類似於Py_Initialize()
。如果 initsigs 為0
,則它會跳過訊號處理程式的初始化註冊,當 CPython 作為大型應用程式的一部分嵌入時,這可能很有用。
-
PyStatus Py_InitializeFromConfig(const PyConfig *config)¶
從 config 配置初始化 Python,如 使用 PyConfig 初始化 中所述。
有關預初始化直譯器、填充執行時配置結構和查詢返回的狀態結構的詳細資訊,請參閱 Python 初始化配置 部分。
-
int Py_IsInitialized()¶
- 屬於 穩定 ABI 的一部分。
當 Python 直譯器已初始化時返回 true(非零),如果未初始化則返回 false(零)。在呼叫
Py_FinalizeEx()
之後,此函式將返回 false,直到再次呼叫Py_Initialize()
。
-
int Py_IsFinalizing()¶
- 自 3.13 版本起,屬於 穩定 ABI 的一部分。
如果主 Python 直譯器正在 關閉,則返回 true(非零)。否則返回 false(零)。
3.13 版本中新增。
-
int Py_FinalizeEx()¶
- 自 3.6 版本起,屬於 穩定 ABI 的一部分。
撤消
Py_Initialize()
所做的所有初始化以及後續對 Python/C API 函式的使用,並銷燬自上次呼叫Py_Initialize()
以來建立但尚未銷燬的所有子直譯器(請參閱下面的Py_NewInterpreter()
)。理想情況下,這將釋放 Python 直譯器分配的所有記憶體。如果第二次呼叫此函式(在未先呼叫Py_Initialize()
的情況下),則此函式不執行任何操作。由於這是
Py_Initialize()
的反向操作,因此應在同一執行緒中以相同活動的直譯器呼叫它。這意味著主執行緒和主直譯器。當Py_RunMain()
正在執行時,絕不應呼叫此函式。通常,返回值是
0
。如果在終止期間(重新整理緩衝資料)出現錯誤,則返回-1
。提供此函式的原因有很多。嵌入式應用程式可能希望在無需重新啟動應用程式本身的情況下重新啟動 Python。從動態可載入庫(或 DLL)載入 Python 直譯器的應用程式可能希望在解除安裝 DLL 之前釋放 Python 分配的所有記憶體。在應用程式中查詢記憶體洩漏期間,開發人員可能希望在從應用程式退出之前釋放 Python 分配的所有記憶體。
Bug 和注意事項: 模組和模組中物件的銷燬以隨機順序完成;當解構函式(
__del__()
方法)依賴於其他物件(甚至函式)或模組時,這可能會導致其失敗。Python 載入的動態載入的擴充套件模組不會解除安裝。Python 直譯器分配的少量記憶體可能不會釋放(如果您發現記憶體洩漏,請報告)。物件之間的迴圈引用佔用的記憶體不會釋放。擴充套件模組分配的某些記憶體可能不會釋放。如果多次呼叫它們的初始化例程,則某些擴充套件可能無法正常工作;如果應用程式多次呼叫Py_Initialize()
和Py_FinalizeEx()
,則可能會發生這種情況。引發一個 審計事件
cpython._PySys_ClearAuditHooks
,不帶任何引數。3.6 版本中新增。
-
void Py_Finalize()¶
- 屬於 穩定 ABI 的一部分。
這是
Py_FinalizeEx()
的向後相容版本,它忽略返回值。
-
int Py_BytesMain(int argc, char **argv)¶
- 自 3.8 版本起,屬於 穩定 ABI 的一部分。
類似於
Py_Main()
,但 argv 是位元組字串陣列,允許呼叫應用程式將文字解碼步驟委派給 CPython 執行時。3.8 版本中新增。
-
int Py_Main(int argc, wchar_t **argv)¶
- 屬於 穩定 ABI 的一部分。
標準直譯器的主程式,封裝了完整的初始化/最終化週期,以及從環境和命令列讀取配置設定的附加行為,然後根據命令列執行
__main__
。此功能適用於希望支援完整的 CPython 命令列介面,而不僅僅是將 Python 執行時嵌入到更大的應用程式中的程式。
argc 和 argv 引數類似於傳遞給 C 程式的
main()
函式的引數,只是 argv 條目首先使用Py_DecodeLocale()
轉換為wchar_t
。 同樣重要的是要注意,引數列表條目可能會被修改以指向與傳入的字串不同的字串(但是,引數列表指向的字串的內容不會被修改)。如果直譯器正常退出(即沒有異常),則返回值將為
0
;如果直譯器因異常退出,則返回值將為1
;如果引數列表不表示有效的 Python 命令列,則返回值將為2
。請注意,如果引發了原本未處理的
SystemExit
,則只要未設定Py_InspectFlag
,此函式將不會返回1
,而是退出程序。如果設定了Py_InspectFlag
,執行將進入互動式 Python 提示符,此時,第二個未處理的SystemExit
仍將退出程序,而任何其他退出方式都將如上所述設定返回值。就執行時配置部分中記錄的 CPython 執行時配置 API 而言(且不考慮錯誤處理),
Py_Main
大致等效於PyConfig config; PyConfig_InitPythonConfig(&config); PyConfig_SetArgv(&config, argc, argv); Py_InitializeFromConfig(&config); PyConfig_Clear(&config); Py_RunMain();
在正常使用中,嵌入應用程式將呼叫此函式,而不是 直接呼叫
Py_Initialize()
、Py_InitializeEx()
或Py_InitializeFromConfig()
,並且所有設定都將按本文件的其他地方所述應用。如果此函式是在先前的執行時初始化 API 呼叫之後呼叫的,則哪些環境和命令列配置設定將被更新取決於版本(因為它取決於哪些設定在執行時首次初始化時已正確支援在設定一次後進行修改)。
-
int Py_RunMain(void)¶
在完全配置的 CPython 執行時中執行主模組。
執行在命令列或配置中指定的命令(
PyConfig.run_command
)、指令碼(PyConfig.run_filename
)或模組(PyConfig.run_module
)。如果未設定這些值,則使用__main__
模組的全域性名稱空間執行互動式 Python 提示符 (REPL)。如果未設定
PyConfig.inspect
(預設值),則如果直譯器正常退出(即沒有引發異常),則返回值將為0
;如果直譯器因異常退出,則返回值將為1
。如果引發了原本未處理的SystemExit
,則該函式將立即退出程序,而不是返回1
。如果設定了
PyConfig.inspect
(例如,當使用-i
選項時),則在直譯器退出時,執行不會返回,而是在使用__main__
模組的全域性名稱空間的互動式 Python 提示符 (REPL) 中恢復。如果直譯器因異常而退出,它會立即在 REPL 會話中引發。然後,函式返回值由 REPL 會話 終止的方式確定:如果會話在沒有引發未處理異常的情況下終止,則返回0
;對於未處理的SystemExit
,則立即退出;對於任何其他未處理的異常,則返回1
。此函式始終會最終化 Python 直譯器,無論它是返回值還是因未處理的
SystemExit
異常而立即退出程序。有關使用
Py_RunMain()
始終以隔離模式執行的自定義 Python 的示例,請參閱 Python 配置。
-
int PyUnstable_AtExit(PyInterpreterState *interp, void (*func)(void*), void *data)¶
- 這是不穩定 API。 它可能會在次要版本中更改,恕不另行通知。
為目標直譯器 interp 註冊一個
atexit
回撥。 這類似於Py_AtExit()
,但為回撥採用顯式的直譯器和資料指標。必須為 interp 持有 GIL。
3.13 版本中新增。
程序範圍的引數¶
-
void Py_SetProgramName(const wchar_t *name)¶
- 屬於 穩定 ABI 的一部分。
保留此 API 以實現向後相容性:應改用設定
PyConfig.program_name
,請參閱 Python 初始化配置。如果呼叫此函式,則應在第一次呼叫
Py_Initialize()
之前呼叫此函式。 它告訴直譯器程式的main()
函式的argv[0]
引數的值(轉換為寬字元)。Py_GetPath()
和下面的一些其他函式使用它來查詢相對於直譯器可執行檔案的 Python 執行時庫。 預設值為'python'
。 引數應指向靜態儲存中的以零結尾的寬字串,該字串的內容在程式執行期間不會更改。 Python 直譯器中的任何程式碼都不會更改此儲存的內容。使用
Py_DecodeLocale()
解碼位元組字串以獲取 wchar_* 字串。自 3.11 版本起已棄用。
-
wchar_t *Py_GetProgramName()¶
- 屬於 穩定 ABI 的一部分。
返回使用
PyConfig.program_name
設定的程式名稱,或者預設名稱。返回的字串指向靜態儲存區;呼叫者不應修改其值。此函式不應在
Py_Initialize()
之前呼叫,否則將返回NULL
。在 3.10 版本中更改: 如果在此函式在
Py_Initialize()
之前呼叫,則現在返回NULL
。自 3.13 版本起已棄用,將在 3.15 版本中刪除: 請改用
sys.executable
。
-
wchar_t *Py_GetPrefix()¶
- 屬於 穩定 ABI 的一部分。
返回已安裝的平臺無關檔案的字首。這是透過一些複雜的規則從使用
PyConfig.program_name
設定的程式名稱和一些環境變數派生而來的;例如,如果程式名稱是'/usr/local/bin/python'
,則字首是'/usr/local'
。返回的字串指向靜態儲存區;呼叫者不應修改其值。這對應於頂層Makefile
中的 prefix 變數以及構建時 configure 指令碼的--prefix
引數。該值在 Python 程式碼中可用作sys.base_prefix
。它僅在 Unix 上有用。另請參閱下一個函式。此函式不應在
Py_Initialize()
之前呼叫,否則將返回NULL
。在 3.10 版本中更改: 如果在此函式在
Py_Initialize()
之前呼叫,則現在返回NULL
。自 3.13 版本起已棄用,將在 3.15 版本中刪除: 請改用
sys.base_prefix
,或者如果需要處理虛擬環境,請使用sys.prefix
。
-
wchar_t *Py_GetExecPrefix()¶
- 屬於 穩定 ABI 的一部分。
返回已安裝的平臺相關檔案的執行字首。這是透過一些複雜的規則從使用
PyConfig.program_name
設定的程式名稱和一些環境變數派生而來的;例如,如果程式名稱是'/usr/local/bin/python'
,則執行字首是'/usr/local'
。返回的字串指向靜態儲存區;呼叫者不應修改其值。這對應於頂層Makefile
中的 exec_prefix 變數以及構建時 configure 指令碼的--exec-prefix
引數。該值在 Python 程式碼中可用作sys.base_exec_prefix
。它僅在 Unix 上有用。背景:當平臺相關檔案(例如可執行檔案和共享庫)安裝在不同的目錄樹中時,執行字首與字首不同。在典型的安裝中,平臺相關檔案可以安裝在
/usr/local/plat
子樹中,而平臺無關檔案可以安裝在/usr/local
中。一般來說,平臺是硬體和軟體系列的組合,例如,執行 Solaris 2.x 作業系統的 Sparc 機器被認為是同一平臺,但執行 Solaris 2.x 的 Intel 機器是另一個平臺,而執行 Linux 的 Intel 機器又是另一個平臺。同一作業系統不同主要版本通常也構成不同的平臺。非 Unix 作業系統則是另一回事;這些系統上的安裝策略差異很大,以至於字首和執行字首沒有意義,並設定為空字串。請注意,編譯後的 Python 位元組碼檔案是平臺無關的(但並非獨立於編譯它們的 Python 版本!)。
系統管理員將知道如何配置 mount 或 automount 程式以在平臺之間共享
/usr/local
,同時使/usr/local/plat
成為每個平臺不同的檔案系統。此函式不應在
Py_Initialize()
之前呼叫,否則將返回NULL
。在 3.10 版本中更改: 如果在此函式在
Py_Initialize()
之前呼叫,則現在返回NULL
。自 3.13 版本起已棄用,將在 3.15 版本中刪除: 請改用
sys.base_exec_prefix
,或者如果需要處理虛擬環境,請使用sys.exec_prefix
。
-
wchar_t *Py_GetProgramFullPath()¶
- 屬於 穩定 ABI 的一部分。
返回 Python 可執行檔案的完整程式名稱;這是從程式名稱(由
PyConfig.program_name
設定)派生預設模組搜尋路徑的副作用計算出來的。返回的字串指向靜態儲存區;呼叫者不應修改其值。該值在 Python 程式碼中可用作sys.executable
。此函式不應在
Py_Initialize()
之前呼叫,否則將返回NULL
。在 3.10 版本中更改: 如果在此函式在
Py_Initialize()
之前呼叫,則現在返回NULL
。自 3.13 版本起已棄用,將在 3.15 版本中刪除: 請改用
sys.executable
。
-
wchar_t *Py_GetPath()¶
- 屬於 穩定 ABI 的一部分。
返回預設模組搜尋路徑;這是從程式名稱(由
PyConfig.program_name
設定)和一些環境變數計算出來的。返回的字串由一系列以平臺相關分隔符分隔的目錄名稱組成。分隔符在 Unix 和 macOS 上是':'
,在 Windows 上是';'
。返回的字串指向靜態儲存區;呼叫者不應修改其值。列表sys.path
在直譯器啟動時使用此值初始化;它可以(並且通常是)在以後修改以更改載入模組的搜尋路徑。此函式不應在
Py_Initialize()
之前呼叫,否則將返回NULL
。在 3.10 版本中更改: 如果在此函式在
Py_Initialize()
之前呼叫,則現在返回NULL
。自 3.13 版本起已棄用,將在 3.15 版本中刪除: 請改用
sys.path
。
-
const char *Py_GetVersion()¶
- 屬於 穩定 ABI 的一部分。
返回此 Python 直譯器的版本。這是一個類似於以下的字串
"3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
第一個單詞(直到第一個空格字元)是當前的 Python 版本;前幾個字元是主要版本和次要版本,用句點分隔。返回的字串指向靜態儲存區;呼叫者不應修改其值。該值在 Python 程式碼中可用作
sys.version
。另請參閱
Py_Version
常量。
-
const char *Py_GetPlatform()¶
- 屬於 穩定 ABI 的一部分。
返回當前平臺的平臺識別符號。在 Unix 上,它由作業系統的“官方”名稱組成,轉換為小寫,後跟主要修訂號;例如,對於也稱為 SunOS 5.x 的 Solaris 2.x,該值為
'sunos5'
。在 macOS 上,它是'darwin'
。在 Windows 上,它是'win'
。返回的字串指向靜態儲存區;呼叫者不應修改其值。該值在 Python 程式碼中可用作sys.platform
。
-
const char *Py_GetCopyright()¶
- 屬於 穩定 ABI 的一部分。
返回當前 Python 版本的官方版權字串,例如:
'Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam'
返回的字串指向靜態儲存區;呼叫者不應修改其值。該值在 Python 程式碼中可作為
sys.copyright
使用。
-
const char *Py_GetCompiler()¶
- 屬於 穩定 ABI 的一部分。
返回一個指示用於構建當前 Python 版本的編譯器的字串,用方括號括起來,例如:
"[GCC 2.7.2.2]"
返回的字串指向靜態儲存區;呼叫者不應修改其值。該值在 Python 程式碼中可作為變數
sys.version
的一部分使用。
-
const char *Py_GetBuildInfo()¶
- 屬於 穩定 ABI 的一部分。
返回有關當前 Python 直譯器例項的序列號、構建日期和時間的資訊,例如:
"#67, Aug 1 1997, 22:34:28"
返回的字串指向靜態儲存區;呼叫者不應修改其值。該值在 Python 程式碼中可作為變數
sys.version
的一部分使用。
-
void PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath)¶
- 屬於 穩定 ABI 的一部分。
保留此 API 是為了向後相容:應使用設定
PyConfig.argv
、PyConfig.parse_argv
和PyConfig.safe_path
,請參閱 Python 初始化配置。基於 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_* 字串。另請參閱
PyConfig.orig_argv
和PyConfig.argv
,它們是 Python 初始化配置 的成員。注意
建議將 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 版本中新增。
自 3.11 版本起已棄用。
-
void PySys_SetArgv(int argc, wchar_t **argv)¶
- 屬於 穩定 ABI 的一部分。
保留此 API 是為了向後相容:應使用設定
PyConfig.argv
和PyConfig.parse_argv
,請參閱 Python 初始化配置。此函式的工作方式類似於
PySys_SetArgvEx()
,其中 updatepath 設定為1
,除非使用-I
選項啟動了 python 直譯器。使用
Py_DecodeLocale()
解碼位元組字串以獲取 wchar_* 字串。另請參閱
PyConfig.orig_argv
和PyConfig.argv
,它們是 Python 初始化配置 的成員。在 3.4 版本中更改: updatepath 值取決於
-I
。自 3.11 版本起已棄用。
-
void Py_SetPythonHome(const wchar_t *home)¶
- 屬於 穩定 ABI 的一部分。
保留此 API 是為了向後相容:應使用設定
PyConfig.home
,請參閱 Python 初始化配置。設定預設的“home”目錄,即標準 Python 庫的位置。有關引數字串的含義,請參閱
PYTHONHOME
。此引數應指向靜態儲存區中以零結尾的字元字串,該字串的內容在程式執行期間不會更改。Python 直譯器中的任何程式碼都不會更改此儲存區的內容。
使用
Py_DecodeLocale()
解碼位元組字串以獲取 wchar_* 字串。自 3.11 版本起已棄用。
-
wchar_t *Py_GetPythonHome()¶
- 屬於 穩定 ABI 的一部分。
返回預設的“home”,即
PyConfig.home
設定的值,或者如果設定了PYTHONHOME
環境變數,則返回其值。此函式不應在
Py_Initialize()
之前呼叫,否則將返回NULL
。在 3.10 版本中更改: 如果在此函式在
Py_Initialize()
之前呼叫,則現在返回NULL
。自 3.13 版本起棄用, 將在 3.15 版本中移除: 請改為獲取
PyConfig.home
或PYTHONHOME
環境變數。
執行緒狀態和全域性直譯器鎖¶
Python 直譯器不是完全執行緒安全的。為了支援多執行緒 Python 程式,存在一個全域性鎖,稱為全域性直譯器鎖或GIL,當前執行緒必須持有該鎖才能安全地訪問 Python 物件。如果沒有鎖,即使是最簡單的操作也可能在多執行緒程式中導致問題:例如,當兩個執行緒同時遞增同一物件的引用計數時,引用計數可能最終只遞增一次而不是兩次。
因此,規則規定,只有獲取了 GIL 的執行緒才能操作 Python 物件或呼叫 Python/C API 函式。為了模擬併發執行,直譯器會定期嘗試切換執行緒(請參閱 sys.setswitchinterval()
)。在讀取或寫入檔案等可能阻塞的 I/O 操作期間,也會釋放鎖,以便其他 Python 執行緒可以同時執行。
Python 直譯器將一些執行緒特定的簿記資訊儲存在名為 PyThreadState
的資料結構中。還有一個全域性變數指向當前的 PyThreadState
:可以使用 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.
這種情況非常普遍,因此存在一對宏來簡化它
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 建立的執行緒¶
當使用專用的 Python API(例如 threading
模組)建立執行緒時,會自動將執行緒狀態與它們關聯,因此上面顯示的程式碼是正確的。但是,當從 C 建立執行緒時(例如,由具有自己執行緒管理的第三方庫建立),它們不持有 GIL,也沒有它們的執行緒狀態結構。
如果需要從這些執行緒呼叫 Python 程式碼(通常這將是上述第三方庫提供的回撥 API 的一部分),則必須首先透過建立執行緒狀態資料結構向直譯器註冊這些執行緒,然後獲取 GIL,最後儲存其執行緒狀態指標,然後才能開始使用 Python/C API。完成後,應重置執行緒狀態指標,釋放 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_*
函式假設只有一個全域性直譯器(由 Py_Initialize()
自動建立)。Python 支援建立其他直譯器(使用 Py_NewInterpreter()
),但不支援混合使用多個直譯器和 PyGILState_*
API。
關於 fork() 的注意事項¶
關於執行緒,另一個需要注意的重要事項是它們在面對 C fork()
呼叫時的行為。在大多數帶有 fork()
的系統上,在程序 fork 之後,只有發出 fork 的執行緒才會存在。這對鎖的處理方式以及 CPython 執行時中的所有儲存狀態都有具體影響。
僅保留“當前”執行緒這一事實意味著其他執行緒持有的任何鎖都將永遠不會被釋放。Python 透過在 fork 之前獲取其內部使用的鎖並在之後釋放它們來解決 os.fork()
的問題。此外,它會重置子程序中的任何 鎖物件。在擴充套件或嵌入 Python 時,無法通知 Python 在 fork 之前需要獲取或在 fork 之後需要重置的其他(非 Python)鎖。需要使用諸如 pthread_atfork()
之類的作業系統工具來完成相同的操作。此外,在擴充套件或嵌入 Python 時,直接呼叫 fork()
而不是透過 os.fork()
(並返回或呼叫 Python)可能會導致死鎖,因為 Python 的內部鎖之一被 fork 後失效的執行緒持有。PyOS_AfterFork_Child()
嘗試重置必要的鎖,但並非總是能夠成功。
所有其他執行緒都消失的事實也意味著必須正確清理 CPython 的執行時狀態,而 os.fork()
會執行此操作。這意味著最終確定當前直譯器擁有的所有其他 PyThreadState
物件和所有其他 PyInterpreterState
物件。由於此原因以及 “主”直譯器 的特殊性,fork()
只能在該直譯器的“主”執行緒中呼叫,在該執行緒中最初初始化了 CPython 全域性執行時。唯一的例外是如果 exec()
將在之後立即被呼叫。
高階 API¶
這些是在編寫 C 擴充套件程式碼或嵌入 Python 直譯器時最常用的型別和函式
-
type PyInterpreterState¶
- 是 有限 API 的一部分(作為不透明結構)。
此資料結構表示多個協作執行緒共享的狀態。屬於同一直譯器的執行緒共享其模組管理和一些其他內部項。此結構中沒有公共成員。
屬於不同直譯器的執行緒最初不共享任何內容,除了程序狀態(如可用記憶體、開啟的檔案描述符等)。全域性直譯器鎖也由所有執行緒共享,無論它們屬於哪個直譯器。
-
type PyThreadState¶
- 是 有限 API 的一部分(作為不透明結構)。
此資料結構表示單個執行緒的狀態。唯一的公共資料成員是
-
PyInterpreterState *interp¶
此執行緒的直譯器狀態。
-
PyInterpreterState *interp¶
-
void PyEval_InitThreads()¶
- 屬於 穩定 ABI 的一部分。
已棄用的函式,不執行任何操作。
在 Python 3.6 及更早的版本中,如果 GIL 不存在,此函式會建立它。
在 3.9 版本中更改:該函式現在不執行任何操作。
在 3.7 版本中更改:此函式現在由
Py_Initialize()
呼叫,因此您不必再自己呼叫它。在 3.2 版本中更改:此函式不能在
Py_Initialize()
之前呼叫。自 3.9 版本起已棄用。
-
PyThreadState *PyEval_SaveThread()¶
- 屬於 穩定 ABI 的一部分。
釋放全域性直譯器鎖(如果已建立),並將執行緒狀態重置為
NULL
,返回之前的執行緒狀態(不為NULL
)。如果鎖已建立,則當前執行緒必須已獲取該鎖。
-
void PyEval_RestoreThread(PyThreadState *tstate)¶
- 屬於 穩定 ABI 的一部分。
獲取全域性直譯器鎖(如果已建立),並將執行緒狀態設定為 tstate,該值不能為
NULL
。如果鎖已建立,則當前執行緒不得獲取該鎖,否則會導致死鎖。注意
在執行時正在完成時從執行緒呼叫此函式將終止該執行緒,即使該執行緒不是由 Python 建立的。您可以使用
Py_IsFinalizing()
或sys.is_finalizing()
來檢查直譯器是否正在完成過程中,以避免不必要的終止。
-
PyThreadState *PyThreadState_Get()¶
- 屬於 穩定 ABI 的一部分。
返回當前執行緒狀態。必須持有全域性直譯器鎖。噹噹前執行緒狀態為
NULL
時,這將發出致命錯誤(以便呼叫者不必檢查NULL
)。
-
PyThreadState *PyThreadState_GetUnchecked()¶
類似於
PyThreadState_Get()
,但如果為 NULL,則不會導致程序因致命錯誤而終止。呼叫者負責檢查結果是否為 NULL。3.13 版本新增: 在 Python 3.5 到 3.12 中,該函式是私有的,被稱為
_PyThreadState_UncheckedGet()
。
-
PyThreadState *PyThreadState_Swap(PyThreadState *tstate)¶
- 屬於 穩定 ABI 的一部分。
將當前執行緒狀態與引數 tstate 給定的執行緒狀態交換,tstate 可以為
NULL
。必須持有全域性直譯器鎖,並且不會釋放該鎖。
以下函式使用執行緒區域性儲存,與子直譯器不相容
-
PyGILState_STATE PyGILState_Ensure()¶
- 屬於 穩定 ABI 的一部分。
確保當前執行緒已準備好呼叫 Python C API,無論 Python 的當前狀態或全域性直譯器鎖的狀態如何。只要每個呼叫都與對
PyGILState_Release()
的呼叫相匹配,一個執行緒可以根據需要多次呼叫此函式。通常,只要在 Release() 之前將執行緒狀態恢復到之前的狀態,就可以在PyGILState_Ensure()
和PyGILState_Release()
呼叫之間使用其他與執行緒相關的 API。例如,正常使用Py_BEGIN_ALLOW_THREADS
和Py_END_ALLOW_THREADS
宏是可以接受的。返回值是呼叫
PyGILState_Ensure()
時執行緒狀態的不透明“控制代碼”,必須將其傳遞給PyGILState_Release()
,以確保 Python 保持相同的狀態。即使允許遞迴呼叫,這些控制代碼不能共享 - 每次對PyGILState_Ensure()
的唯一呼叫都必須儲存其對PyGILState_Release()
的呼叫控制代碼。當函式返回時,當前執行緒將持有 GIL,並且能夠呼叫任意 Python 程式碼。失敗是致命錯誤。
注意
在執行時正在完成時從執行緒呼叫此函式將終止該執行緒,即使該執行緒不是由 Python 建立的。您可以使用
Py_IsFinalizing()
或sys.is_finalizing()
來檢查直譯器是否正在完成過程中,以避免不必要的終止。
-
void PyGILState_Release(PyGILState_STATE)¶
- 屬於 穩定 ABI 的一部分。
釋放之前獲取的任何資源。在此呼叫之後,Python 的狀態將與相應的
PyGILState_Ensure()
呼叫之前的狀態相同(但通常此狀態對於呼叫者是未知的,因此使用 GILState API)。每次呼叫
PyGILState_Ensure()
都必須與同一執行緒上的PyGILState_Release()
呼叫相匹配。
-
PyThreadState *PyGILState_GetThisThreadState()¶
- 屬於 穩定 ABI 的一部分。
獲取此執行緒的當前執行緒狀態。如果在當前執行緒上沒有使用過 GILState API,則可能返回
NULL
。請注意,主執行緒始終具有這樣的執行緒狀態,即使在主執行緒上沒有進行自動執行緒狀態呼叫也是如此。這主要是一個輔助/診斷函式。
-
int PyGILState_Check()¶
如果當前執行緒持有 GIL,則返回
1
,否則返回0
。可以隨時從任何執行緒呼叫此函式。只有當它已初始化其 Python 執行緒狀態並且當前持有 GIL 時,它才會返回1
。這主要是一個輔助/診斷函式。例如,在回撥上下文或記憶體分配函式中,當知道 GIL 被鎖定時,它可以允許呼叫者執行敏感操作或以其他方式表現不同,這可能很有用。在 3.4 版本中新增。
以下宏通常不帶尾隨分號使用;在 Python 原始碼發行版中查詢示例用法。
-
Py_BEGIN_ALLOW_THREADS¶
- 屬於 穩定 ABI 的一部分。
此宏擴充套件為
{ PyThreadState *_save; _save = PyEval_SaveThread();
。請注意,它包含一個左大括號;它必須與後面的Py_END_ALLOW_THREADS
宏相匹配。有關此宏的進一步討論,請參見上文。
-
Py_END_ALLOW_THREADS¶
- 屬於 穩定 ABI 的一部分。
此宏擴充套件為
PyEval_RestoreThread(_save); }
。請注意,它包含一個右大括號;它必須與之前的Py_BEGIN_ALLOW_THREADS
宏相匹配。有關此宏的進一步討論,請參見上文。
-
Py_BLOCK_THREADS¶
- 屬於 穩定 ABI 的一部分。
此宏擴充套件為
PyEval_RestoreThread(_save);
:它等效於Py_END_ALLOW_THREADS
,但不包含右大括號。
-
Py_UNBLOCK_THREADS¶
- 屬於 穩定 ABI 的一部分。
此宏擴充套件為
_save = PyEval_SaveThread();
:它等效於Py_BEGIN_ALLOW_THREADS
,但不包含左大括號和變數宣告。
底層 API¶
以下所有函式都必須在 Py_Initialize()
之後呼叫。
在 3.7 版本中變更: Py_Initialize()
現在初始化 GIL。
-
PyInterpreterState *PyInterpreterState_New()¶
- 屬於 穩定 ABI 的一部分。
建立一個新的直譯器狀態物件。全域性直譯器鎖不需要持有,但如果需要序列化對此函式的呼叫,則可以持有。
引發一個審計事件
cpython.PyInterpreterState_New
,不帶任何引數。
-
void PyInterpreterState_Clear(PyInterpreterState *interp)¶
- 屬於 穩定 ABI 的一部分。
重置直譯器狀態物件中的所有資訊。必須持有全域性直譯器鎖。
引發一個審計事件
cpython.PyInterpreterState_Clear
,不帶任何引數。
-
void PyInterpreterState_Delete(PyInterpreterState *interp)¶
- 屬於 穩定 ABI 的一部分。
銷燬一個直譯器狀態物件。全域性直譯器鎖不需要持有。直譯器狀態必須已透過先前對
PyInterpreterState_Clear()
的呼叫重置。
-
PyThreadState *PyThreadState_New(PyInterpreterState *interp)¶
- 屬於 穩定 ABI 的一部分。
建立一個屬於給定直譯器物件的新的執行緒狀態物件。全域性直譯器鎖不需要持有,但如果需要序列化對此函式的呼叫,則可以持有。
-
void PyThreadState_Clear(PyThreadState *tstate)¶
- 屬於 穩定 ABI 的一部分。
重置執行緒狀態物件中的所有資訊。必須持有全域性直譯器鎖。
在 3.9 版本中變更: 此函式現在呼叫
PyThreadState.on_delete
回撥。之前,這發生在PyThreadState_Delete()
中。在 3.13 版本中變更:
PyThreadState.on_delete
回撥已移除。
-
void PyThreadState_Delete(PyThreadState *tstate)¶
- 屬於 穩定 ABI 的一部分。
銷燬一個執行緒狀態物件。全域性直譯器鎖不需要持有。執行緒狀態必須已透過先前對
PyThreadState_Clear()
的呼叫重置。
-
void PyThreadState_DeleteCurrent(void)¶
銷燬當前執行緒狀態並釋放全域性直譯器鎖。與
PyThreadState_Delete()
一樣,必須持有全域性直譯器鎖。執行緒狀態必須已透過先前對PyThreadState_Clear()
的呼叫重置。
-
PyFrameObject *PyThreadState_GetFrame(PyThreadState *tstate)¶
- 自 3.10 版本起為穩定 ABI的一部分。
獲取 Python 執行緒狀態 tstate 的當前幀。
返回一個強引用。如果當前沒有執行幀,則返回
NULL
。另請參閱
PyEval_GetFrame()
。tstate 不得為
NULL
。在 3.9 版本中新增。
-
uint64_t PyThreadState_GetID(PyThreadState *tstate)¶
- 自 3.10 版本起為穩定 ABI的一部分。
獲取 Python 執行緒狀態 tstate 的唯一執行緒狀態識別符號。
tstate 不得為
NULL
。在 3.9 版本中新增。
-
PyInterpreterState *PyThreadState_GetInterpreter(PyThreadState *tstate)¶
- 自 3.10 版本起為穩定 ABI的一部分。
獲取 Python 執行緒狀態 tstate 的直譯器。
tstate 不得為
NULL
。在 3.9 版本中新增。
-
void PyThreadState_EnterTracing(PyThreadState *tstate)¶
暫停 Python 執行緒狀態 tstate 中的跟蹤和效能分析。
使用
PyThreadState_LeaveTracing()
函式恢復它們。在 3.11 版本中新增。
-
void PyThreadState_LeaveTracing(PyThreadState *tstate)¶
恢復 Python 執行緒狀態 tstate 中被
PyThreadState_EnterTracing()
函式暫停的跟蹤和效能分析。另請參閱
PyEval_SetTrace()
和PyEval_SetProfile()
函式。在 3.11 版本中新增。
-
PyInterpreterState *PyInterpreterState_Get(void)¶
- 自 3.9 版本起為穩定 ABI的一部分。
獲取當前直譯器。
如果當前沒有 Python 執行緒狀態或沒有當前直譯器,則發出致命錯誤。它不能返回 NULL。
呼叫者必須持有 GIL。
在 3.9 版本中新增。
-
int64_t PyInterpreterState_GetID(PyInterpreterState *interp)¶
- 自 3.7 版本起為穩定 ABI的一部分。
返回直譯器的唯一 ID。如果執行此操作時出現任何錯誤,則返回
-1
並設定錯誤。呼叫者必須持有 GIL。
在 3.7 版本中新增。
-
PyObject *PyInterpreterState_GetDict(PyInterpreterState *interp)¶
- 自 3.8 版本起,屬於 穩定 ABI 的一部分。
返回一個字典,可在其中儲存特定於直譯器的資料。如果此函式返回
NULL
,則沒有引發異常,並且呼叫方應假定沒有可用的特定於直譯器的字典。這不能替代
PyModule_GetState()
,擴充套件應該使用它來儲存特定於直譯器的狀態資訊。3.8 版本中新增。
-
typedef PyObject *(*_PyFrameEvalFunction)(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)¶
幀評估函式的型別。
throwflag 引數由生成器的
throw()
方法使用:如果非零,則處理當前異常。在 3.9 版本中變更: 該函式現在接受一個 tstate 引數。
在 3.11 版本中變更: frame 引數從
PyFrameObject*
更改為_PyInterpreterFrame*
。
-
_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()¶
- 返回值:借用的引用。屬於 穩定 ABI 的一部分。
返回一個字典,擴充套件可以在其中儲存執行緒特定的狀態資訊。每個擴充套件都應該使用一個唯一的鍵來在該字典中儲存狀態。當沒有當前執行緒狀態可用時,呼叫此函式是可以的。如果此函式返回
NULL
,則不會引發異常,並且呼叫者應該假定沒有可用的當前執行緒狀態。
-
int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)¶
- 屬於 穩定 ABI 的一部分。
線上程中非同步引發異常。id 引數是目標執行緒的執行緒 id;exc 是要引發的異常物件。此函式不竊取對 exc 的任何引用。為了防止幼稚的誤用,您必須編寫自己的 C 擴充套件來呼叫此函式。必須在持有 GIL 的情況下呼叫。返回修改的執行緒狀態數;這通常是一個,但如果找不到執行緒 id,則為零。如果 exc 是
NULL
,則清除該執行緒的待處理異常(如果有)。這不會引發任何異常。在 3.7 版本中變更: id 引數的型別從 long 更改為 unsigned long。
-
void PyEval_AcquireThread(PyThreadState *tstate)¶
- 屬於 穩定 ABI 的一部分。
獲取全域性直譯器鎖,並將當前執行緒狀態設定為 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)¶
- 屬於 穩定 ABI 的一部分。
將當前執行緒狀態重置為
NULL
並釋放全域性直譯器鎖。該鎖必須先前已建立,並且必須由當前執行緒持有。tstate 引數不能為NULL
,僅用於檢查它是否表示當前執行緒狀態 - 如果不是,則會報告致命錯誤。PyEval_SaveThread()
是一個更高級別的函式,它始終可用(即使執行緒尚未初始化)。
子直譯器支援¶
雖然在大多數情況下,您只會嵌入單個 Python 直譯器,但在某些情況下,您需要在同一程序中,甚至在同一執行緒中建立多個獨立的直譯器。子直譯器允許您執行此操作。
“主”直譯器是在執行時初始化時建立的第一個直譯器。它通常是程序中唯一的 Python 直譯器。與子直譯器不同,主直譯器具有獨特的程序全域性責任,如訊號處理。它還負責執行時初始化期間的執行,並且通常是執行時最終化期間的活動直譯器。PyInterpreterState_Main()
函式返回指向其狀態的指標。
您可以使用 PyThreadState_Swap()
函式在子直譯器之間切換。您可以使用以下函式建立和銷燬它們
-
type PyInterpreterConfig¶
包含配置子直譯器的大多數引數的結構。它的值僅在
Py_NewInterpreterFromConfig()
中使用,並且永遠不會被執行時修改。在 3.12 版本中新增。
結構欄位
-
int use_main_obmalloc¶
如果此值為
0
,則子直譯器將使用其自己的“物件”分配器狀態。否則,它將使用(共享)主直譯器的狀態。如果此值為
0
,則check_multi_interp_extensions
必須為1
(非零)。如果此值為1
,則gil
不能為PyInterpreterConfig_OWN_GIL
。
-
int allow_fork¶
如果此值為
0
,則執行時將不支援在任何子直譯器當前處於活動狀態的執行緒中 fork 程序。否則,fork 操作不受限制。請注意,當 fork 操作被停用時,
subprocess
模組仍然有效。
-
int allow_exec¶
如果此值為
0
,則執行時將不支援在任何子直譯器當前處於活動狀態的執行緒中透過 exec (例如os.execv()
) 替換當前程序。否則,exec 操作不受限制。請注意,當 exec 操作被停用時,
subprocess
模組仍然有效。
-
int allow_daemon_threads¶
如果此值為
0
,則子直譯器的threading
模組將不會建立守護執行緒。否則,允許建立守護執行緒(只要allow_threads
為非零值)。
-
int check_multi_interp_extensions¶
如果此值為
0
,則可以在任何子直譯器當前處於活動狀態的執行緒中匯入所有擴充套件模組,包括舊的(單階段初始化)模組。否則,只能匯入多階段初始化擴充套件模組(請參見 PEP 489)。(另請參見Py_mod_multiple_interpreters
。)如果
use_main_obmalloc
為0
,則此值必須為1
(非零)。
-
int gil¶
此值決定子直譯器的 GIL 的操作。它可以是以下值之一
-
PyInterpreterConfig_DEFAULT_GIL¶
使用預設選擇 (
PyInterpreterConfig_SHARED_GIL
)。
-
PyInterpreterConfig_SHARED_GIL¶
使用(共享)主直譯器的 GIL。
-
PyInterpreterConfig_OWN_GIL¶
使用子直譯器自己的 GIL。
如果此值為
PyInterpreterConfig_OWN_GIL
,則PyInterpreterConfig.use_main_obmalloc
必須為0
。-
PyInterpreterConfig_DEFAULT_GIL¶
-
int use_main_obmalloc¶
-
PyStatus Py_NewInterpreterFromConfig(PyThreadState **tstate_p, const PyInterpreterConfig *config)¶
建立一個新的子直譯器。這為執行 Python 程式碼提供了一個(幾乎)完全獨立的環境。特別是,新直譯器擁有所有匯入模組的單獨、獨立版本,包括基本模組
builtins
、__main__
和sys
。載入的模組表(sys.modules
)和模組搜尋路徑(sys.path
)也是獨立的。新環境沒有sys.argv
變數。它具有新的標準 I/O 流檔案物件sys.stdin
、sys.stdout
和sys.stderr
(但是這些都指向相同的底層檔案描述符)。給定的 config 控制直譯器初始化的選項。
成功後,tstate_p 將設定為新子直譯器中建立的第一個執行緒狀態。此執行緒狀態在當前執行緒狀態中建立。請注意,沒有建立實際執行緒;請參閱下面的執行緒狀態討論。如果新直譯器的建立不成功,則 tstate_p 將設定為
NULL
;不會設定異常,因為異常狀態儲存在當前執行緒狀態中,並且可能沒有當前執行緒狀態。與所有其他 Python/C API 函式一樣,在呼叫此函式之前必須持有全域性直譯器鎖,並且在它返回時仍然持有。同樣,在進入時必須設定當前執行緒狀態。成功後,返回的執行緒狀態將設定為當前狀態。如果子直譯器是用自己的 GIL 建立的,則呼叫直譯器的 GIL 將被釋放。當函式返回時,當前執行緒將持有新直譯器的 GIL,並且先前直譯器的 GIL 將在此處保持釋放狀態。
在 3.12 版本中新增。
當子直譯器彼此隔離,並限制某些功能時,它們最有效。
PyInterpreterConfig config = { .use_main_obmalloc = 0, .allow_fork = 0, .allow_exec = 0, .allow_threads = 1, .allow_daemon_threads = 0, .check_multi_interp_extensions = 1, .gil = PyInterpreterConfig_OWN_GIL, }; PyThreadState *tstate = NULL; PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config); if (PyStatus_Exception(status)) { Py_ExitStatusException(status); }
請注意,配置僅在短時間內使用,並且不會被修改。在初始化期間,配置的值會轉換為各種
PyInterpreterState
值。配置的只讀副本可以儲存在PyInterpreterState
的內部。擴充套件模組在(子)直譯器之間共享,如下所示
對於使用多階段初始化的模組,例如
PyModule_FromDefAndSpec()
,會為每個直譯器建立和初始化單獨的模組物件。只有 C 級別的靜態和全域性變數在這些模組物件之間共享。對於使用單階段初始化的模組,例如
PyModule_Create()
,首次匯入特定擴充套件時,會正常初始化它,並儲存其模組字典的(淺)副本。當另一個(子)直譯器匯入相同的擴充套件時,會初始化一個新模組,並用此副本的內容填充它;不會呼叫擴充套件的init
函式。因此,模組字典中的物件最終會在(子)直譯器之間共享,這可能會導致不必要的行為(請參閱下面的 錯誤和注意事項)。請注意,這與透過呼叫
Py_FinalizeEx()
和Py_Initialize()
完全重新初始化直譯器後匯入擴充套件時發生的情況不同;在這種情況下,會再次呼叫擴充套件的initmodule
函式。與多階段初始化一樣,這意味著只有 C 級別的靜態和全域性變數在這些模組之間共享。
-
PyThreadState *Py_NewInterpreter(void)¶
- 屬於 穩定 ABI 的一部分。
建立一個新的子直譯器。這本質上只是對
Py_NewInterpreterFromConfig()
的一個封裝,使用一個保留現有行為的配置。結果是一個非隔離的子直譯器,它與主直譯器共享 GIL,允許 fork/exec,允許守護執行緒,並允許單階段初始化模組。
-
void Py_EndInterpreter(PyThreadState *tstate)¶
- 屬於 穩定 ABI 的一部分。
銷燬由給定執行緒狀態表示的(子)直譯器。給定的執行緒狀態必須是當前執行緒狀態。請參閱下面的執行緒狀態討論。當呼叫返回時,當前執行緒狀態為
NULL
。與此直譯器關聯的所有執行緒狀態都將被銷燬。在呼叫此函式之前,必須持有目標直譯器使用的全域性直譯器鎖。當它返回時,不持有 GIL。Py_FinalizeEx()
將銷燬所有在此時未被顯式銷燬的子直譯器。
每個直譯器一個 GIL¶
使用 Py_NewInterpreterFromConfig()
,你可以建立一個與其他直譯器完全隔離的子直譯器,包括擁有自己的 GIL。這種隔離最重要的好處是,這樣的直譯器可以在不被其他直譯器阻塞或阻塞任何其他直譯器的情況下執行 Python 程式碼。因此,當執行 Python 程式碼時,單個 Python 程序可以真正利用多個 CPU 核心。隔離還鼓勵採用與僅使用執行緒不同的併發方法。(參見 PEP 554。)
使用隔離的直譯器需要警惕地維護這種隔離。這尤其意味著在沒有關於執行緒安全的保證的情況下,不要共享任何物件或可變狀態。即使是原本不可變的物件(例如,None
,(1, 5)
)通常也無法共享,因為引用計數。一種簡單但效率較低的方法是在某些狀態(或物件)的所有使用周圍使用全域性鎖。或者,透過將它們設為 不朽的,可以使有效的不可變物件(如整數或字串)在引用計數方面保持安全。事實上,內建單例、小整數和許多其他內建物件已經完成了這一點。
如果你保持隔離,那麼你將可以訪問正確的多核計算,而不會出現自由執行緒帶來的複雜性。未能保持隔離會將你暴露在自由執行緒的全部後果中,包括競爭和難以除錯的崩潰。
除此之外,使用多個隔離直譯器的主要挑戰之一是如何在它們之間安全地通訊(不破壞隔離)和高效地通訊。執行時和 stdlib 尚未提供任何標準的通訊方法。未來的 stdlib 模組將有助於減少保持隔離的工作量,並公開在直譯器之間通訊(和共享)資料的有效工具。
在 3.12 版本中新增。
錯誤和注意事項¶
由於子直譯器(和主直譯器)是同一程序的一部分,它們之間的隔離並不完美——例如,使用低階檔案操作(如 os.close()
)它們可以(意外或惡意地)影響彼此開啟的檔案。由於擴充套件在(子)直譯器之間共享的方式,某些擴充套件可能無法正常工作;當使用單階段初始化或(靜態)全域性變數時,這種情況尤其可能發生。可以將在一個子直譯器中建立的物件插入到另一個(子)直譯器的名稱空間中;如果可能,應避免這種情況。
應特別注意避免在子直譯器之間共享使用者定義的函式、方法、例項或類,因為此類物件執行的匯入操作可能會影響錯誤的(子)直譯器的已載入模組字典。同樣重要的是避免共享可以訪問上述物件的物件。
另請注意,將此功能與 PyGILState_*
API 結合使用是微妙的,因為這些 API 假設 Python 執行緒狀態和作業系統級執行緒之間存在雙射關係,而子直譯器的存在會破壞這種假設。強烈建議不要在匹配的 PyGILState_Ensure()
和 PyGILState_Release()
呼叫之間切換子直譯器。此外,使用這些 API 以允許從非 Python 建立的執行緒呼叫 Python 程式碼的擴充套件(例如 ctypes
)在使用子直譯器時可能會被破壞。
非同步通知¶
提供了一種機制,可以向主直譯器執行緒發出非同步通知。這些通知採用函式指標和 void 指標引數的形式。
-
int Py_AddPendingCall(int (*func)(void*), void *arg)¶
- 屬於 穩定 ABI 的一部分。
計劃一個函式從主直譯器執行緒呼叫。成功時,返回
0
,並且將 func 排隊以在主執行緒中呼叫。失敗時,返回-1
,而不設定任何異常。成功排隊後,func 將最終從主直譯器執行緒中呼叫,引數為 arg。它將相對於正常執行的 Python 程式碼非同步呼叫,但滿足這兩個條件
func 必須在成功時返回
0
,在失敗時返回-1
並設定異常。不會中斷 func 來遞迴執行另一個非同步通知,但如果釋放全域性直譯器鎖,它仍然可能被中斷以切換執行緒。此函式不需要當前執行緒狀態即可執行,也不需要全域性直譯器鎖。
要在子直譯器中呼叫此函式,呼叫方必須持有 GIL。否則,可以將函式 func 安排為從錯誤的直譯器呼叫。
警告
這是一個低階函式,僅在非常特殊的情況下有用。不能保證 func 會盡快被呼叫。如果主執行緒正忙於執行系統呼叫,則在系統呼叫返回之前不會呼叫 func。此函式通常不適合從任意 C 執行緒呼叫 Python 程式碼。而是使用 PyGILState API。
在版本 3.1 中新增。
在 3.9 版本中更改: 如果此函式在子直譯器中呼叫,則現在安排從子直譯器而不是從主直譯器呼叫函式 func。每個子直譯器現在都有自己的計劃呼叫列表。
效能分析和跟蹤¶
Python 直譯器為附加效能分析和執行跟蹤工具提供了一些底層支援。這些用於效能分析、除錯和覆蓋率分析工具。
此 C 介面允許效能分析或跟蹤程式碼避免透過 Python 級可呼叫物件呼叫的開銷,而是直接進行 C 函式呼叫。該工具的基本屬性沒有改變;該介面允許為每個執行緒安裝跟蹤函式,並且報告給跟蹤函式的基本事件與以前版本中報告給 Python 級跟蹤函式的事件相同。
-
typedef int (*Py_tracefunc)(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg)¶
使用
PyEval_SetProfile()
和PyEval_SetTrace()
註冊的跟蹤函式的型別。第一個引數是傳遞給註冊函式的物件,作為 obj,frame 是事件所屬的幀物件,what 是常量PyTrace_CALL
,PyTrace_EXCEPTION
,PyTrace_LINE
,PyTrace_RETURN
,PyTrace_C_CALL
,PyTrace_C_EXCEPTION
,PyTrace_C_RETURN
或PyTrace_OPCODE
之一,arg 取決於 what 的值。what 的值
arg 的含義
總是
Py_None
。由
sys.exc_info()
返回的異常資訊。總是
Py_None
。返回給呼叫者的值,如果是由異常引起的則為
NULL
。正在被呼叫的函式物件。
正在被呼叫的函式物件。
正在被呼叫的函式物件。
總是
Py_None
。
-
int PyTrace_CALL¶
當報告對函式或方法的新呼叫,或新進入生成器時,作為
Py_tracefunc
函式的 what 引數的值。請注意,生成器函式的迭代器的建立不會報告,因為沒有控制轉移到相應幀中的 Python 位元組碼。
-
int PyTrace_EXCEPTION¶
當引發異常時,作為
Py_tracefunc
函式的 what 引數的值。當在執行幀中設定異常後處理任何位元組碼之後,使用此 what 值呼叫回撥函式。這樣做的效果是,當異常傳播導致 Python 堆疊展開時,當異常傳播時,將在返回到每個幀時呼叫回撥。只有跟蹤函式會接收到這些事件;分析器不需要它們。
-
int PyTrace_LINE¶
當報告行號事件時,傳遞給
Py_tracefunc
函式(但不是分析函式)的 what 引數的值。可以透過將該幀上的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
。另請參閱
sys.setprofile()
函式。呼叫者必須持有 GIL。
-
void PyEval_SetProfileAllThreads(Py_tracefunc func, PyObject *obj)¶
類似於
PyEval_SetProfile()
,但在當前直譯器中所有正在執行的執行緒中設定分析函式,而不是僅在當前執行緒上設定。呼叫者必須持有 GIL。
與
PyEval_SetProfile()
一樣,此函式會忽略在所有執行緒中設定分析函式時引發的任何異常。
在 3.12 版本中新增。
-
void PyEval_SetTrace(Py_tracefunc func, PyObject *obj)¶
將跟蹤函式設定為 func。這類似於
PyEval_SetProfile()
,但跟蹤函式會接收行號事件和每操作碼事件,但不會接收任何與 C 函式物件被呼叫相關的事件。使用PyEval_SetTrace()
註冊的任何跟蹤函式都不會接收PyTrace_C_CALL
、PyTrace_C_EXCEPTION
或PyTrace_C_RETURN
作為 what 引數的值。另請參閱
sys.settrace()
函式。呼叫者必須持有 GIL。
-
void PyEval_SetTraceAllThreads(Py_tracefunc func, PyObject *obj)¶
與
PyEval_SetTrace()
類似,但在屬於當前直譯器的所有正在執行的執行緒中設定跟蹤函式,而不是僅在當前執行緒中設定。呼叫者必須持有 GIL。
與
PyEval_SetTrace()
一樣,此函式會忽略在所有執行緒中設定跟蹤函式時引發的任何異常。
在 3.12 版本中新增。
引用跟蹤¶
3.13 版本中新增。
-
typedef int (*PyRefTracer)(PyObject*, int event, void *data)¶
使用
PyRefTracer_SetTracer()
註冊的跟蹤函式的型別。第一個引數是一個剛建立的 Python 物件(當 event 設定為PyRefTracer_CREATE
時)或即將被銷燬的物件(當 event 設定為PyRefTracer_DESTROY
時)。data 引數是在呼叫PyRefTracer_SetTracer()
時提供的不透明指標。
3.13 版本中新增。
-
int PyRefTracer_CREATE¶
當 Python 物件已建立時,
PyRefTracer
函式的 event 引數的值。
-
int PyRefTracer_DESTROY¶
當 Python 物件已被銷燬時,
PyRefTracer
函式的 event 引數的值。
-
int PyRefTracer_SetTracer(PyRefTracer tracer, void *data)¶
註冊引用跟蹤函式。當建立新的 Python 物件或即將銷燬物件時,將呼叫此函式。如果提供了 data,則它必須是一個不透明指標,該指標將在呼叫跟蹤函式時提供。成功時返回
0
。發生錯誤時,設定異常並返回-1
。請注意,跟蹤函式不得在內部建立 Python 物件,否則呼叫將是可重入的。跟蹤器也不得清除任何現有異常或設定異常。每次呼叫跟蹤函式時,都會持有 GIL。
呼叫此函式時必須持有 GIL。
3.13 版本中新增。
-
PyRefTracer PyRefTracer_GetTracer(void **data)¶
獲取註冊的引用跟蹤函式以及在呼叫
PyRefTracer_SetTracer()
時註冊的不透明資料指標的值。如果未註冊任何跟蹤器,此函式將返回 NULL,並將 data 指標設定為 NULL。呼叫此函式時必須持有 GIL。
3.13 版本中新增。
高階偵錯程式支援¶
這些函式僅供高階除錯工具使用。
-
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 直譯器為執行緒區域性儲存 (TLS) 提供底層支援,該支援包裝了底層本機 TLS 實現,以支援 Python 級執行緒區域性儲存 API (threading.local
)。CPython C 級 API 類似於 pthreads 和 Windows 提供的 API:使用執行緒鍵和函式來關聯每個執行緒的 void* 值。
呼叫這些函式時,不需要持有 GIL;它們提供自己的鎖定。
請注意,Python.h
不包含 TLS API 的宣告,您需要包含 pythread.h
才能使用執行緒區域性儲存。
注意
這些 API 函式均不代表 void* 值處理記憶體管理。您需要自己分配和釋放它們。如果 void* 值恰好是 PyObject*,則這些函式也不會對它們執行引用計數操作。
執行緒特定儲存 (TSS) API¶
引入 TSS API 是為了取代在 CPython 直譯器中使用現有 TLS API。此 API 使用新的型別 Py_tss_t
而不是 int 來表示執行緒鍵。
在 3.7 版本中新增。
另請參閱
“CPython 中執行緒區域性儲存的新 C-API” (PEP 539)
-
type Py_tss_t¶
此資料結構表示執行緒鍵的狀態,其定義可能取決於底層 TLS 實現,並且它具有一個表示鍵初始化狀態的內部欄位。此結構中沒有公共成員。
當未定義 Py_LIMITED_API 時,允許透過
Py_tss_NEEDS_INIT
靜態分配此型別。
-
Py_tss_NEEDS_INIT¶
此宏展開為
Py_tss_t
變數的初始化器。 請注意,在使用了 Py_LIMITED_API 的情況下,此宏將不會被定義。
動態分配¶
在用 Py_LIMITED_API 構建的擴充套件模組中,需要動態分配 Py_tss_t
,因為此型別的靜態分配是不可能的,因為其實現方式在構建時是不透明的。
-
Py_tss_t *PyThread_tss_alloc()¶
- 自 3.7 版本起為穩定 ABI的一部分。
返回一個與使用
Py_tss_NEEDS_INIT
初始化後的值具有相同狀態的值,或者在動態分配失敗的情況下返回NULL
。
-
void PyThread_tss_free(Py_tss_t *key)¶
- 自 3.7 版本起為穩定 ABI的一部分。
釋放由
PyThread_tss_alloc()
分配的給定 key ,並在此之前先呼叫PyThread_tss_delete()
來確保所有關聯的執行緒區域性變數都已被取消賦值。 如果 key 引數為NULL
,則這是一個空操作。注意
一個被釋放的鍵會變成懸空指標。 你應該將該鍵重置為
NULL
。
方法¶
這些函式的引數 key 不能為 NULL
。 此外,如果給定的 Py_tss_t
未透過 PyThread_tss_create()
初始化,則 PyThread_tss_set()
和 PyThread_tss_get()
的行為是未定義的。
-
int PyThread_tss_is_created(Py_tss_t *key)¶
- 自 3.7 版本起為穩定 ABI的一部分。
如果給定的
Py_tss_t
已透過PyThread_tss_create()
初始化,則返回一個非零值。
-
int PyThread_tss_create(Py_tss_t *key)¶
- 自 3.7 版本起為穩定 ABI的一部分。
成功初始化 TSS 鍵時返回零值。 如果 key 引數指向的值不是透過
Py_tss_NEEDS_INIT
初始化的,則行為是未定義的。 此函式可以對同一個鍵重複呼叫 – 對已初始化的鍵呼叫它是一個空操作,並立即返回成功。
-
void PyThread_tss_delete(Py_tss_t *key)¶
- 自 3.7 版本起為穩定 ABI的一部分。
銷燬一個 TSS 鍵以忘記跨所有執行緒與該鍵關聯的值,並將該鍵的初始化狀態更改為未初始化。 銷燬的鍵可以透過
PyThread_tss_create()
再次初始化。 此函式可以對同一個鍵重複呼叫 – 對已銷燬的鍵呼叫它是一個空操作。
執行緒區域性儲存 (TLS) API¶
自 3.7 版本起已棄用: 此 API 已被 執行緒特定儲存 (TSS) API 取代。
注意
此版本的 API 不支援本機 TLS 鍵的定義方式不能安全地強制轉換為 int
的平臺。 在此類平臺上,PyThread_create_key()
將立即返回失敗狀態,並且其他 TLS 函式在此類平臺上都將為空操作。
由於上面提到的相容性問題,不應在新程式碼中使用此版本的 API。
同步原語¶
C-API 提供基本的互斥鎖。
-
type PyMutex¶
互斥鎖。
PyMutex
應該初始化為零,以表示未鎖定狀態。 例如PyMutex mutex = {0};
PyMutex
的例項不應複製或移動。PyMutex
的內容和地址都是有意義的,它必須保持在記憶體中的固定可寫位置。注意
PyMutex
當前佔用一個位元組,但該大小應被認為是不穩定的。 大小可能會在未來的 Python 版本中更改,而不會有棄用期。3.13 版本中新增。
-
void PyMutex_Lock(PyMutex *m)¶
鎖定互斥鎖 m。如果另一個執行緒已經鎖定了它,則呼叫執行緒將阻塞,直到互斥鎖被解鎖。在阻塞期間,如果持有 GIL,執行緒將臨時釋放它。
3.13 版本中新增。
Python 臨界區 API¶
臨界區 API 為 自由執行緒 CPython 上的每個物件鎖提供了一個死鎖避免層。它們旨在取代對 全域性直譯器鎖 的依賴,並且在具有全域性直譯器鎖的 Python 版本中是空操作。
臨界區透過在呼叫 PyEval_SaveThread()
期間隱式掛起活動臨界區並釋放鎖來避免死鎖。當呼叫 PyEval_RestoreThread()
時,將恢復最近的臨界區,並重新獲取其鎖。這意味著臨界區 API 提供的保證比傳統鎖弱 - 它們之所以有用,是因為它們的行為類似於 GIL。
宏使用的函式和結構暴露出來,以便在 C 宏不可用的情況下使用。它們應該只按照給定的宏展開中使用。請注意,結構的尺寸和內容可能會在未來的 Python 版本中發生變化。
注意
需要一次鎖定兩個物件的操作必須使用 Py_BEGIN_CRITICAL_SECTION2
。你*不能*使用巢狀的臨界區來一次鎖定多個物件,因為內部臨界區可能會掛起外部臨界區。此 API 不提供一次鎖定兩個以上物件的方法。
示例用法
static PyObject *
set_field(MyObject *self, PyObject *value)
{
Py_BEGIN_CRITICAL_SECTION(self);
Py_SETREF(self->field, Py_XNewRef(value));
Py_END_CRITICAL_SECTION();
Py_RETURN_NONE;
}
在上面的示例中,Py_SETREF
呼叫 Py_DECREF
,後者可以透過物件的釋放函式呼叫任意程式碼。臨界區 API 透過允許執行時在終結器觸發的程式碼阻塞並呼叫 PyEval_SaveThread()
時臨時掛起臨界區,從而避免了由於重入和鎖順序導致的潛在死鎖。
-
Py_BEGIN_CRITICAL_SECTION(op)¶
獲取物件 op 的每個物件鎖,並開始一個臨界區。
在自由執行緒構建中,此宏展開為
{ PyCriticalSection _py_cs; PyCriticalSection_Begin(&_py_cs, (PyObject*)(op))
在預設構建中,此宏展開為
{
。3.13 版本中新增。
-
Py_END_CRITICAL_SECTION()¶
結束臨界區並釋放每個物件鎖。
在自由執行緒構建中,此宏展開為
PyCriticalSection_End(&_py_cs); }
在預設構建中,此宏展開為
}
。3.13 版本中新增。
-
Py_BEGIN_CRITICAL_SECTION2(a, b)¶
獲取物件 a 和 b 的每個物件鎖,並開始一個臨界區。鎖以一致的順序(先最低地址)獲取,以避免鎖順序死鎖。
在自由執行緒構建中,此宏展開為
{ PyCriticalSection2 _py_cs2; PyCriticalSection2_Begin(&_py_cs2, (PyObject*)(a), (PyObject*)(b))
在預設構建中,此宏展開為
{
。3.13 版本中新增。
-
Py_END_CRITICAL_SECTION2()¶
結束臨界區並釋放每個物件鎖。
在自由執行緒構建中,此宏展開為
PyCriticalSection2_End(&_py_cs2); }
在預設構建中,此宏展開為
}
。3.13 版本中新增。