为什么线程在CPU之间传播?

时间:2016-02-06 07:41:33

标签: python multithreading

我正试图了解线程与CPU使用情况。关于线程与多处理有很多讨论(好的概述是this answer)因此我决定通过在运行Windows 10,Python 3.4的8 CPU笔记本电脑上启动最大线程数来测试这一点。

我的假设是所有线程都绑定到一个CPU。

编辑:事实证明这不是一个好的假设。我现在明白,对于多线程代码,只能一次运行一个的python代码(无论在哪个核心/哪个核心)。对于多处理代码(其中进程是独立的并且确实独立运行),这是不同的 虽然我读到了这些差异,但one answer实际上澄清了这一点。

我认为这也解释了下面的CPU视图:它是许多线程分布在许多CPU上的平均视图,但只有一个在一个给定时间运行(#34;平均值"到所有CPU)他们一直在跑。)

这不是链接问题的重复(它解决了相反的问题,即一个核心上的所有线程),如果某人有一天有类似的问题并希望我的启蒙有所帮助,我会留下它。 / p>

代码

import threading
import time


def calc():
    time.sleep(5)
    while True:
        a = 2356^36

n = 0
while True:
    try:
        n += 1
        t = threading.Thread(target=calc)
        t.start()
    except RuntimeError:
        print("max threads: {n}".format(n=n))
        break
    else:
        print('.')

time.sleep(100000)

导致889个线程正在启​​动。

enter image description here

然而,CPU上的负载是分布式的(对于纯CPU计算而言,这个负载非常低,否则,当不运行我的脚本时,笔记本电脑在空载时空闲):

enter image description here

为什么会这样?线程是否经常在CPU之间移动,我看到的只是一个平均值(现实是在给定时刻所有线程都在一个CPU上)?或者他们确实分发了?

2 个答案:

答案 0 :(得分:3)

截至今天仍然是'一个线程持有GIL'的情况。所以一次运行一个线程。

线程在操作系统级别进行管理。发生的事情是每100'滴答'(=解释器指令)正在运行的线程释放GIL并重置滴答计数器。

由于此示例中的线程进行连续计算,因此达到100条指令的滴答限制非常快,导致几乎立即释放GIL并且线程之间的“争斗”开始获取GIL。

所以,我的假设是你的操作系统的负载高于预期,因为(太快)线程切换+几乎连续释放和获取GIL。操作系统花费更多时间进行切换而不是实际进行任何有用的计算。

正如您自己提到的,为了一次使用多个核心,最好查看多处理模块(joblib / Parallel)。

有趣的阅读: http://www.dabeaz.com/python/UnderstandingGIL.pdf

答案 1 :(得分:-1)

庵。多线程的关键是确保它们的工作分散开来。一个非常简单的欺骗是使用与CPU核心一样多的线程。关键是它们都是独立的,所以它们实际上可以同时运行。如果它们位于同一个核心上,那么一次只有一个线程可以真正运行。他们来回传递该核心以便在操作系统级别进行处理。

你的假设是错误的和奇怪的。什么会让你认为他们应该在相同的CPU上运行,因此以1/8的速度运行?因为解决这些问题的唯一原因通常是让整个批次比单个核心更快。

事实上,您认为编写并行代码到底是为了不同时在多个内核上独立运行?像这样毫无意义且难以做到,让我们进行复杂的提取,分支和分支例程来完成比仅仅插入数据的核心更慢的事情吗?