import time start = time.clock() def CountDown(n): while n > 0: n -= 1 CountDown(100000) print("Time used:",(time.clock() - start))运行结果为:
Time used: 0.0039529000000000005
import time from threading import Thread start = time.clock() def CountDown(n): while n > 0: n -= 1 t1 = Thread(target=CountDown, args=[100000 // 2]) t2 = Thread(target=CountDown, args=[100000 // 2]) t1.start() t2.start() t1.join() t2.join() print("Time used:",(time.clock() - start))运行结果为:
Time used: 0.006673
可以看到,此程序中使用了 2 个线程来执行和上面代码相同的工作,但从输出结果中可以看到,运行效率非但没有提高,反而降低了。是不是和你猜想的结果不一样?事实上,得到这样的结果是肯定的,因为 GIL 限制了 Python 多线程的性能不会像我们预期的那样。如果使用更多线程进行尝试,会发现其运行效率和 2 个线程效率几乎一样(本机器测试使用 4 个线程,其执行效率约为 0.005)。这里不再给出具体测试代码,有兴趣的读者可自行测试。
>>> import sys
>>> a = []
>>> b = a
>>> sys.getrefcount(a)
3
for (;;) { if (--ticker < 0) { ticker = check_interval; /* Give another thread a chance */ PyThread_release_lock(interpreter_lock); /* Other threads may run now */ PyThread_acquire_lock(interpreter_lock, 1); } bytecode = *next_instr++; switch (bytecode) { /* execute the next instruction ... */ } }从这段代码中可以看出,每个 Python 线程都会先检查 ticker 计数。只有在 ticker 大于 0 的情况下,线程才会去执行自己的代码。
import threading n = 0 def foo(): global n n += 1 threads = [] for i in range(100): t = threading.Thread(target=foo) threads.append(t) for t in threads: t.start() for t in threads: t.join() print(n)执行此代码会发现,其大部分时候会打印 100,但有时也会打印 99 或者 98,原因在于 n+=1 这一句代码让线程并不安全。如果去翻译 foo 这个函数的字节码就会发现,它实际上是由下面四行字节码组成:
>>> import dis
>>> dis.dis(foo)
LOAD_GLOBAL 0 (n)
LOAD_CONST 1 (1)
INPLACE_ADD
STORE_GLOBAL 0 (n)
Copyright © 广州京杭网络科技有限公司 2005-2025 版权所有 粤ICP备16019765号
广州京杭网络科技有限公司 版权所有