为什么非常小的检查间隔不会减慢 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 缓存中)。
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 缓存中)。