Skip to content

Instantly share code, notes, and snippets.

@kindy
Created May 13, 2025 08:27
Show Gist options
  • Save kindy/db243db2f609b46f28116b09f2bbb7f9 to your computer and use it in GitHub Desktop.
Save kindy/db243db2f609b46f28116b09f2bbb7f9 to your computer and use it in GitHub Desktop.
Python GIL test
'''
output:
main [7, 8, 9, 10, 11, 12, 20, 21, 22, 23, 24, 25, 26, 28, 29]
thread [1, 2, 3, 4, 5, 6, 13, 14, 15, 16, 17, 18, 19, 27]
'''
import time
import threading
n = 0
def loop(ret: list[int], d: float, seg: float):
s = time.time()
global n
while time.time() - s < d:
s0 = time.time()
while time.time() - s0 < seg:
pass
n += 1
ret.append(n)
seg = 0.001
total = seg * 20
thread = []
th = threading.Thread(target=loop, args=(thread, total, seg))
th.start()
main = []
loop(main, total, seg)
th.join()
print("main", main)
print("thread", thread)
'''
output:
thread 0
thread 1
thread 2
thread 3
thread 4
thread 5
main 0
thread 6
main 1
thread 7
main 2
thread 8
main 3
main 4
thread 9
main 5
thread 10
main 6
thread 11
main 7
main 8
main 9
main 10
main 11
main 12
main 13
'''
import time
import threading
def loop(prefix: str, d: float, seg: float):
s = time.time()
n = 0
while time.time() - s < d:
s0 = time.time()
while time.time() - s0 < seg:
pass
print(prefix, n, flush=True)
n += 1
seg = 0.001
total = seg * 20
th = threading.Thread(target=loop, args=("thread", total, seg))
th.start()
loop("main", total, seg)
th.join()
@kindy
Copy link
Author

kindy commented May 13, 2025

QA with AI

me:
这段代码在测试Python的GIL,loop函数是热循环,按说一个Thread中的loop应该完全运行完毕,才会把运行权交给另一个Thread,这里看起来print是交错执行的,这是为什么呢?

GitHub Copilot:
Python GIL 与线程执行分析
这段代码确实在测试 Python 的全局解释器锁(GIL),但您关于线程执行的理解有一个误区。

为什么 print 输出会交错执行
在 Python 中,尽管存在 GIL,但 Python 解释器会在以下情况释放并重新获取 GIL:

  1. 时间片轮转:默认情况下,Python 解释器会每隔一小段时间(通常是 5ms)自动释放 GIL,让其他线程有机会执行
  2. I/O 操作:当线程执行 I/O 操作时(如您代码中的 print
  3. 阻塞操作:执行某些系统调用时

在您的代码中:

  • 每个线程运行 loop 函数,该函数包含一个内部循环(while time.time() - s0 < seg
  • 每次内部循环结束后执行 print 语句
  • print 是 I/O 操作,会触发 GIL 的释放
  • 另外,即使没有 I/O,Python 也会定期释放 GIL

所以输出交错的原因是:

  1. 线程 A 运行内部循环 0.03 秒
  2. 线程 A 执行 print,此时释放 GIL
  3. 线程 B 获得 GIL,执行内部循环
  4. 线程 B 执行 print,释放 GIL
  5. 如此交替执行

这与 GIL 的设计是一致的,GIL 并不会让一个线程把所有工作完全做完才交给另一个线程,而是会定期释放给其他线程执行的机会。

如果您想看到更明显的 GIL 效果,可以移除 print 语句,使用更紧凑的 CPU 密集型计算。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment