简介
在Python 3.13版本中,一个重要的变化是GIL(全局解释器锁)的可选性。GIL是CPython解释器为了确保任何时候只有一个线程执行Python字节码而设计的机制。从Python 3.13开始,这个长期存在的限制可能会被解除,允许更多的并发执行。
什么是GIL?
GIL是一个保证同一时间只有一个线程运行的核心机制,这对于单线程执行的Python代码来说是必要的,但对多线程应用来说可能是个瓶颈,因为它限制了真正的并行计算。
实验特性
Python 3.13引入了一个名为“自由线程模式”的新功能,它默认关闭GIL,让多线程能更有效地协同工作。这是一项实验性的特性,如果你想要尝试,可以从官方下载预览版安装,并在安装时选择“自由线程二进制文件(实验)”。
配置GIL
要使GIL在Python 3.13中变为可选,只需在安装时使用--disable-gil
选项,这是一种构建配置,意味着选择了无GIL的构建。此外,还可以通过环境变量PYTHON_GIL
来控制GIL的启用和禁用,设置为1表示启用,0表示禁用。命令行选项-X gil
也有同样的作用。
Python
# v3.13
# GIL disabled
python3 -X gil=0 sample.py
# GIL enabled
python3 -X gil=1 sample.py
检查GIL状态
你可以通过sysconfig.get_config_var("Py_GIL_DISABLED")
来检查当前Python解释器是否启用了无GIL模式。返回值为0表示GIL启用,1表示GIL已禁用。
import sys
sys._is_gil_enabled() # returns a boolean value
GIL与无GIL性能对比
比较GIL启用和禁用时,多线程程序的性能会有显著差异。我们可以通过一个简单的Python程序(gil.py),计算数字的阶乘,来观察单线程、多线程和多进程任务的执行时间。在GIL启用时,多线程和多进程之间的性能差距较小;而在GIL禁用时,多线程性能提升明显,而单线程和多进程任务的性能可能会有所下降。
import sys
import sysconfig
import math
import time
import threading
import multiprocessing
def compute_factorial(n):
return math.factorial(n)
# Single-threaded
def single_threaded_compute(n):
for num in n:
compute_factorial(num)
print("Single-threaded: Factorial Computed.")
# Multi-threaded
def multi_threaded_compute(n):
threads = []
# Create 5 threads
for num in n:
thread = threading.Thread(target=compute_factorial, args=(num,))
threads.append(thread)
thread.start()
# Wait for all threads to complete
for thread in threads:
thread.join()
print("Multi-threaded: Factorial Computed.")
# Multi-process
def multi_processing_compute(n):
processes = []
# Create a process for each number in the list
for num in n:
process = multiprocessing.Process(target=compute_factorial, args=(num,))
processes.append(process)
process.start()
# Wait for all processes to complete
for process in processes:
process.join()
print("Multi-process: Factorial Computed.")
def main():
# Checking Version
print(f"Python version: {sys.version}")
# GIL Status
status = sysconfig.get_config_var("Py_GIL_DISABLED")
if status is None:
print("GIL cannot be disabled")
if status == 0:
print("GIL is active")
if status == 1:
print("GIL is disabled")
numlist = [100000, 200000, 300000, 400000, 500000]
# Single-threaded Execution
start = time.time()
single_threaded_compute(numlist)
end = time.time() - start
print(f"Single-threaded time taken: {end:.2f} seconds")
# Multi-threaded Execution
start = time.time()
multi_threaded_compute(numlist)
end = time.time() - start
print(f"Multi-threaded time taken : {end:.2f} seconds")
# Multi-process Execution
start = time.time()
multi_processing_compute(numlist)
end = time.time() - start
print(f"Multi-process time taken : {end:.2f} seconds")
if __name__ == "__main__":
main()
打开GIL
python gil.py
Python version: 3.12.2 (tags/v3.12.2:6abddd9, Feb 6 2024, 21:26:36) [MSC v.1937 64 bit (AMD64)]
GIL cannot be disabled
Single-threaded: Factorial Computed.
Single-threaded time taken: 9.04 seconds
Multi-threaded: Factorial Computed.
Multi-threaded time taken : 8.21 seconds
Multi-process: Factorial Computed.
Multi-process time taken : 5.64 seconds
禁用GIL
D:/SACHIN/Python13/python3.13t gil.py
Python version: 3.13.0b3 experimental free-threading build (tags/v3.13.0b3:7b41395, Jun 27 2024, 16:17:17) [MSC v.1940 64 bit (AMD64)]
GIL is disabled
Single-threaded: Factorial Computed.
Single-threaded time taken: 9.28 seconds
Multi-threaded: Factorial Computed.
Multi-threaded time taken : 4.86 seconds
Multi-process: Factorial Computed.
Multi-process time taken : 6.14 seconds