为什么非常小的检查间隔不会减慢 CPU 密集型多线程 python3?

Why does a very small checkinterval not slow down CPU-intensive multithreading in python3?

from threading import Thread

def countdown(start, end):
    while end > start:
        end -= 1

def multi_thread(n):
    t1 = Thread(target=countdown, args=(0, n // 2))
    t2 = Thread(target=countdown, args=(n // 2, n))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

if __name__ == '__main__':
    import timeit
    import sys

    sys.setswitchinterval(1)
    print(timeit.timeit("""import gil;gil.multi_thread(10000000);""", number=1))
    # 1.07s
    sys.setswitchinterval(0.001)
    print(timeit.timeit("""import gil;gil.multi_thread(10000000);""", number=1))
    # 1.09s

看完了NewGIL.pdf,我觉得小间隔会导致线程sleep/wakeup操作多,那么总的执行时间应该会长一些。我错了吗?

测试环境:四核Ubuntu16.04 python3.5.

是的,你是对的。 较低的切换间隔意味着将对 GIL 进行更频繁的条件轮询以查看是否可以获取它。 由于 GIL,我们不能 运行 线程并行,更频繁的上下文切换实际上会损害我们的性能。

如果您想提高系统性能,您将不得不使用 multiprocessed 解决方案。

请注意,您的整个任务只需要大约 1 秒。因此,如果开关间隔为 0.001 秒,则只有大约 1/0.001 = 一千次开关 总数 。每个开关(发生 "at C speed")的成本更自然地以微秒而不是毫秒来衡量,因此与 1 秒的总耗时相比,其中一千个开关仍然便宜。

要查看更多效果,请尝试将切换间隔设置为 1e-6

在现实生活中,线程切换的实际成本更多的是 相关的 成本:线程获得足够的时间来填充硬件指令和数据缓存,然后被切换出去并新线程首先在各个级别遭受缓存未命中。您的示例没有任何这些成本(每个线程使用的代码和数据相对较小,并且两个线程的内容甚至可以同时放入 L1 缓存中)。