python3 中,为什么把 checkinterval 设置的非常小没有让 CPU 密集型多线程变慢?

2018-05-20 15:53:38 +08:00
 jfry
from threading import Thread

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

def single_thread(n):
    countdown(0, n)

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

按照我的理解,将切换间隔设置的更小,导致更多次的线程睡眠 /唤醒操作,然后总的执行时间应该变长,但是这里并没有,谁能告诉我是为什么吗? 测试环境为:四核 Ubuntu python3.5

2340 次点击
所在节点    Python
4 条回复
enenaaa
2018-05-20 17:26:25 +08:00
第一, 线程切换时间依赖于操作系统。
第二, 这个值只是解释器估计的理想时间。在执行较长的函数内并不会主动中断。因为解释器没有线程调度功能, 需要依赖系统。
chenxytw
2018-05-21 14:15:52 +08:00
jfry
2018-05-21 20:29:11 +08:00
@enenaaa @chenxytw 我是看了一个讲 Python3 GIL 的 PDF 之后做的这个实验,根据这个 PDF 中的描述,当两个线程 A,B 同时运行的时候,假如 A 正在运行,此时 B 会阻塞直到超时,然后设置 gil_drop_request 为 1,A 检测到之后就会释放 GIL 并且通过信号唤醒 B,因此我理解的是此时操作系统就会让 A 睡眠,然后调度 B .是我理解错了吗?
PDF 地址: http://www.dabeaz.com/python/NewGIL.pdf
enenaaa
2018-05-22 09:53:24 +08:00
@jfry 线程切换的条件一是当前线程主动挂起,二是当前时间片用完。这两个条件都由系统决定,解释器是在系统切换完之后加锁。setswitchinterval 只是在解释器加锁时的一个参照时间,而不是系统的时间片时间。

这个程序里线程一直在运行,用满系统时间片。导致解释器无从按指定参数去控制。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/456294

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX