Python threading.get_ident() 回傳的是 **Python 解釋器內部分配的整數 ID**,非作業系統核心調度的真實執行緒 ID (TID)。在效能分析、系統追蹤 (perf, strace, SystemTap)、綁定 CPU 親和性等場景下,必須獲取 **Linux 核心層面的 TID (即 gettid() 系統呼叫回傳值)**。本文提供完整跨平台解決方案。
| API | 來源 | 用途 | 範例值 |
|---|---|---|---|
threading.get_ident() | Python VM 內部計數器 | 邏輯識別、threading._active 字典鍵 | 140234567890112 |
os.getpid() | 核心 getpid() | 進程 ID (PID) | 12345 |
Linux | 核心 gettid() (syscall 186/224/319 依架構) | 核心調度實體 ID (TID),top -H, ps -T 顯示值 | 12346 |
import ctypes
import threading
import os
# 1. 獲取系統呼叫號 (x86_64 為 186, ARM64 為 178, i386 為 224)
# 建議動態查詢而非硬編碼
def get_syscall_number():
# 方法一:編譯小程式查詢 (需 gcc)
# 方法二:查閱 /usr/include/asm/unistd.h 或 /usr/include/asm-generic/unistd.h
# 方法三:使用 python 內建常數 (Linux 3.3+)
return 186 # x86_64 常見值
SYS_gettid = get_syscall_number()
libc = ctypes.CDLL('libc.so.6', use_errno=True)
def get_tid():
"""回傳當前執行緒的核心 TID"""
return libc.syscall(SYS_gettid)
# 測試
def worker():
print(f"Python ident: {threading.get_ident()}, Kernel TID: {get_tid()}")
threads = [threading.Thread(target=worker) for _ in range(3)]
for t in threads:
t.start()
for t in threads:
t.join()
# 輸出範例:
# Python ident: 140234567890112, Kernel TID: 12346
# Python ident: 140234567890113, Kernel TID: 12347
# Python ident: 140234567890114, Kernel TID: 12348
import platform
import ctypes
def get_gettid_syscall_nr():
machine = platform.machine()
if machine == 'x86_64':
return 186
elif machine == 'aarch64':
return 178
elif machine in ('i386', 'i686'):
return 224
elif machine == 'arm':
return 319 # ARM EABI
elif machine == 'ppc64le':
return 341
elif machine == 'riscv64':
return 178
else:
raise RuntimeError(f"Unsupported architecture: {machine}")
SYS_gettid = get_gettid_syscall_nr()
libc = ctypes.CDLL('libc.so.6', use_errno=True)
gettid = lambda: libc.syscall(SYS_gettid)
threading.get_native_id()
import threading
import sys
if sys.version_info >= (3, 8):
# 官方 API,跨平台 (Linux: gettid, macOS: pthread_threadid_np, Windows: GetThreadId)
print(f"Native TID: {threading.get_native_id()}")
else:
# 回退方案
pass
強烈建議:Python 3.8+ 專案直接使用 threading.get_native_id(),無需手動 ctypes 綁定。
perf record -g -p 產生的報告中執行緒 ID 為 TID,對應 Python 程式碼需映射關係。os.sched_setaffinity(tid, {cpu_id}) 需核心 TID (Python 3.3+ os.sched_setaffinity(0, ...) 僅影響當前執行緒)。strace -p , SystemTap, eBPF 追蹤特定執行緒。
# macOS: pthread_threadid_np(pthread_t, uint64_t*)
import ctypes
import threading
libc = ctypes.CDLL('libc.dylib')
pthread_self = libc.pthread_self
pthread_self.restype = ctypes.c_void_p
pthread_threadid_np = libc.pthread_threadid_np
pthread_threadid_np.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint64)]
pthread_threadid_np.restype = ctypes.c_int
def get_tid_macos():
tid = ctypes.c_uint64()
pthread_threadid_np(pthread_self(), ctypes.byref(tid))
return tid.value
# Windows: GetCurrentThreadId() 回傳 DWORD TID
import ctypes
kernel32 = ctypes.windll.kernel32
GetCurrentThreadId = kernel32.GetCurrentThreadId
GetCurrentThreadId.restype = ctypes.c_ulong
def get_tid_windows():
return GetCurrentThreadId()
# compat_tid.py
import sys
import threading
import ctypes
def get_native_tid():
"""跨平台獲取核心執行緒 ID"""
if sys.version_info >= (3, 8):
return threading.get_native_id()
if sys.platform.startswith('linux'):
# Linux ctypes 方案 (見上文)
...
elif sys.platform == 'darwin':
# macOS 方案 (見上文)
...
elif sys.platform == 'win32':
# Windows 方案 (見上文)
...
else:
raise NotImplementedError(f"Platform {sys.platform} not supported")
# 使用
from compat_tid import get_native_tid
print(f"Current TID: {get_native_tid()}")
threading.get_ident() 在 Python 進程重啟、執行緒池複用時可能重複;TID 由核心全局唯一分配,進程內不重複。gettid() 非 POSIX 標準,但已成為事實標準 (Android, 容器運行時均依賴)。pid_namespace 隔離。Python 3.8+ 內建 threading.get_native_id() 徹底解決了跨平台獲取核心 TID 的歷史痛點。舊版本專案可參考本文 ctypes 方案實現相容封裝。掌握 TID 與 Python 邏輯 ID 的映射關係,是進行深度效能調優、系統級除錯與可觀測性建設的基礎技能。