我正试图了解线程与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个线程正在启动。
然而,CPU上的负载是分布式的(对于纯CPU计算而言,这个负载非常低,否则,当不运行我的脚本时,笔记本电脑在空载时空闲):
为什么会这样?线程是否经常在CPU之间移动,我看到的只是一个平均值(现实是在给定时刻所有线程都在一个CPU上)?或者他们确实分发了?
答案 0 :(得分:3)
截至今天仍然是'一个线程持有GIL'的情况。所以一次运行一个线程。
线程在操作系统级别进行管理。发生的事情是每100'滴答'(=解释器指令)正在运行的线程释放GIL并重置滴答计数器。
由于此示例中的线程进行连续计算,因此达到100条指令的滴答限制非常快,导致几乎立即释放GIL并且线程之间的“争斗”开始获取GIL。
所以,我的假设是你的操作系统的负载高于预期,因为(太快)线程切换+几乎连续释放和获取GIL。操作系统花费更多时间进行切换而不是实际进行任何有用的计算。
正如您自己提到的,为了一次使用多个核心,最好查看多处理模块(joblib / Parallel)。
答案 1 :(得分:-1)
庵。多线程的关键是确保它们的工作分散开来。一个非常简单的欺骗是使用与CPU核心一样多的线程。关键是它们都是独立的,所以它们实际上可以同时运行。如果它们位于同一个核心上,那么一次只有一个线程可以真正运行。他们来回传递该核心以便在操作系统级别进行处理。
你的假设是错误的和奇怪的。什么会让你认为他们应该在相同的CPU上运行,因此以1/8的速度运行?因为解决这些问题的唯一原因通常是让整个批次比单个核心更快。
事实上,您认为编写并行代码到底是为了不同时在多个内核上独立运行?像这样毫无意义且难以做到,让我们进行复杂的提取,分支和分支例程来完成比仅仅插入数据的核心更慢的事情吗?