我想知道是否有一种简单的方法可以“打开”所有100%的CPU,以便我可以更快地运行进程(例如python计算)。
1)这可能吗?
2)是否有简单的方法可以还原到正常状态?
3)如果需要,是否可以使用较少的CPU?
我在想像这样的命令行交互:
pi@raspberry:~ $ sudo turnOnFourCores python run.py
我想知道是否有一种简单的方法可以“打开”所有100%的CPU,以便我可以更快地运行进程(例如python计算)。
1)这可能吗?
2)是否有简单的方法可以还原到正常状态?
3)如果需要,是否可以使用较少的CPU?
我在想像这样的命令行交互:
pi@raspberry:~ $ sudo turnOnFourCores python run.py
Answers:
默认情况下,任何计算机都将尝试使用其所有内核。但是,只有在应用程序为多线程时,它才能实现此目的。如果不是(即不使用该threading
模块的Python脚本),则最多只能使用一个内核。这相当于四核CPU上CPU的25%。如果您想修改脚本以使用多个内核,则可以将计算分为多个部分,并对其进行多线程处理,如Python文档中所示。
正如Anon回答的那样,如果不使用Python的GIL(全局解释器锁),这将无法正常工作。这允许任务同时(看似)运行,但不允许代码跨多个内核运行。如果您使用的是用C语言编写的模块(例如numpy),则它们可以允许您使用多个内核来绕过该限制。此外,如果不是这样,Python将提供multiprocessing,它允许您在多个内核上运行任何任务。
我想知道是否有一种简单的方法可以“打开”所有100%的CPU,以便我可以更快地运行进程(例如python计算)。
我认为您的意思不是这样。这不是pi特有的问题,这也是一个逻辑约束。
目前,仅靠计算机本身还没有很大的能力来确定可以单线程运行的进程可以并行运行。请注意,此时他们可能具有这种能力,因此不需要计算机程序员,因为可以执行此操作的计算机系统也可以编写自己的代码1 .。
考虑以下简单的数学表达式:
(4 + 2) * 17 / (3 + 6)
有可能并行计算,但是在逻辑上是有限的。我会说没有多于两个线程是没有意义的,即使那样,它基本上只会是一个:
#1 a) 4 + 2 b) 6 * 17 c) 102 / 9
#2 a) 3 + 6
线程#2通过计算3 + 6 = 9进行了贡献,线程#1在步骤C中使用了该线程,并节省了一步。但是,就并行性而言,这将是有益的。尽管线程2 可以计算17/9,而线程1 却可以计算6 * 17,但是这样做毫无意义,因为您现在有两个无法重新组合的通往同一目标的不同路径。即,#2可以继续工作:
b) 17 / 9 c) 1.888 * 6
并且最终得到与线程#1(11.333)相同的结果,但是他们在步骤A之后没有互相帮助,因此让他们两个追求这个目标是浪费时间。
(请注意,该示例不是一个字面的示例;它只是为了说明一种逻辑原理。在用户代码中线程执行任务的规模要大得多,但是在多线程编程中,您不需要真正的课程即可掌握这里的想法。)
利用多个处理器需要编写相应的代码。您不能简单地说:“哦,使用所有4个内核,并更快地完成!”。那不会发生的。从逻辑上讲,很多(或大多数)问题和任务涉及无法并行发生的步骤,而这些步骤必须按顺序进行。
1.但请参阅下面的费利克斯·唐贝克(Felix Dombek)的评论;我不是AI方面的专家。值得一提的是,按照彼得·科德(Peter Corde)的评论,操作系统可以利用现代指令集和处理器以并行方式优化非常细粒度的事物,并且硬件管道也可以做到这一点,尽管不能跨内核(单个核心执行的事情不止一件事,即在最终执行之前的不同时间对指令流进行操作。我试图在此处坚持用户线程的主题,因为我认为这或多或少是您所要获得的。
add
指令彼此相邻放置来利用ILP,以便它们可以在同一条指令中运行时钟周期。如您所指出的,下面的乘除法余数将通过数据依赖关系进行序列化。
使用多个内核需要将线程级并行性显式公开给OS,这通常需要程序员编写多线程程序。(或者在不同的输入上多次运行单线程程序,例如使用进行编译make -j4
)
不过,某些语言的编译器支持自动并行化。例如,带有OpenMP的C或C ++可以将普通for()
循环编译为启动多个线程的程序。
#pragma omp parallel for
for(int i = 0; i < 1000000; ++i)
{
A[i] = B[i] * constant + C[i];
}
但是,这仍然必须在编写或编译程序时发生。 当前的硬件和操作系统无法使用多个内核来加速单线程程序。
相关:单个线程如何在多个内核上运行?:答案:他们没有。但是还有其他种类的并行性,例如指令级并行性,单个CPU内核发现并利用该并行度运行单个线程的速度比一次执行一条指令快。
关于这个问题,我的回答将详细介绍现代CPU如何查找和利用细粒度的指令级并行性。(主要关注x86)。通过同时运行多个指令,这只是正常CPU工作方式的一部分,而无需特别启用。(通过性能计数器,您可以查看执行一个程序时CPU设法在每个时钟上运行多少条指令,或者采取其他措施。)
请注意,RPi3使用有序的ARM Cortex-A53 CPU内核。每个内核是2宽超标量(ILP允许的每个时钟2条指令),但是不能对指令重新排序以找到更多的指令级并行度并隐藏延迟。
尽管如此,CPU仍是流水线,所以飞行中的指令总数(从获取和解码一直到流水线末端的回写阶段)仍然很重要。当数据依赖性不受限制时,CPU正在处理的每个管道阶段可以有2条指令,每个时钟的吞吐量为2条指令。(这是2宽的意思。)
它不能无序执行指令,但是通过谨慎的指令排序(通常由编译器执行),它仍然可以隐藏一条指令的等待时间,该指令需要多个周期才能准备好其输出。(例如,即使加载到高速缓存中或进行乘法运算,加载都将花费多个周期,而下一个周期要准备好加法)。技巧是对asm指令进行排序,以便在产生结果的那一条与使用结果的那一条之间有多个独立的指令。
让软件(编译器)静态地调度指令要比拥有可以在内部重新排序同时保留以程序顺序运行的幻想的硬件脆弱。对于编译器而言,即使是很小的无序窗口也很难像重新排列指令那样出色地完成工作,因为缓存丢失是不可预测的,并且在编译时很难分析跨函数调用的依赖链。并且没有硬件寄存器重新命名就限制了寄存器的数量。
当您的代码运行速度比您想要的慢时,所有这些都会给您带来一点安慰。当然,Cortex-A53的引擎盖下有很多很酷的东西,而Cortex-A57的引擎盖下还有很多很酷的东西(例如每个时钟最多3条指令的无序执行),甚至更多像Skylake这样的大型x86 CPU(更不用说时钟速度的差异了)。
与https://en.wikipedia.org/wiki/Classic_RISC_pipeline相比,Cortex-A53很棒,就像您在计算机体系结构课程中将要学习的原始MIPS一样,但是按照现代标准,它是相当低端的。
java
不是myapp.jar
,并且肯定不是单线程的。
这根本不是CPU的工作原理。
从目前的情况来看,假设您的CPU不会由于80摄氏度或更高的温度相关问题而受到限制,则完全可以100%使用。话虽如此,您(通常)不想看到CPU固定在100%。如果您的CPU利用率通常为100%,则处理器可能要处理的过多。这将导致结结和普遍不愉快的用户体验。
与更实际的东西进行比较,您的CPU利用率很像汽车。这辆车可能能够以每小时100英里的速度行驶,但是您的车速表很有可能会在该速度下读取一些东西。在城里时,您可能永远无法达到每小时25英里的速度。但是这并不能改变汽车可以以每小时100英里的速度行驶。您只是没有足够努力地推动加速器。
如果您只是简单地使RPi做更多的事情(将更多的推子推到加速器上),您将看到CPU利用率上升。例如,yes
在终端窗口中运行命令时请注意CPU的使用情况(请记住,这将ctrl+c
结束终端命令)。这将使您的CPU增加25%,因为它将使您的四个CPU内核之一最大化。
其他答案确实提供了很好的细节,但似乎并没有专门解决您的问题。
注意:
如果您想提高pi的整体性能,则可能需要研究Overclocking。这样可以使CPU以更快的速度运行。缺点是发热量增加,处理器寿命降低以及功耗增加。
我认为OP可能无法完全理解多核/多线程编程的概念以及充分利用100%的多核有多困难,除非该算法可以轻松地变成一个令人尴尬的并行问题。
有关更多信息,您可以阅读更多有关著名文章标题“免费午餐结束”的信息,网址为http://www.gotw.ca/publications/concurrency-ddj.htm
由于OP在他的问题中未指定python,因此我想建议两种较新的语言,它们在Raspberry Pi上可以正常工作,并且具有使用并发的非常简单的方法。
我目前最喜欢的是Rust语言。我已经在Pi上编写和编译了程序。Rust很好,因为它可以防止多种类型的指针和竞争条件错误,这使得编写并发代码既容易又安全。Rust本来是一种系统编程语言,但它几乎可以完成C可以做的任何事情。
另一种这样的语言是Go(也称为Golang,以使其更易于搜索)。Go是由Google团队创建的,是一种相当成熟的语言。在Go中制作协程很容易,他们称之为“ Go例程”。
这两种语言都可以在Raspberry Pi甚至Pi Zero上编译代码。但是,它们都可以从速度更快的计算机进行交叉编译,这对于大型程序而言是不错的选择。