- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经设计了一种算法,现在我正在研究实现以在多核上解决它。基本上我给每个核心相同的问题,我会选择得分最高的解决方案。但是,我注意到使用多核会减慢代码的运行时间,但我不明白为什么。所以我创建了一个非常简单的示例来展示相同的行为。我有一个简单的 Algoritmn 类:
算法.h
class Algorithm
{
public:
Algorithm() : mDummy(0) {};
void runAlgorithm();
protected:
long mDummy;
};
算法.cpp
#include "algorithm.h"
void Algorithm::runAlgorithm()
{
long long k = 0;
for (long long i = 0; i < 200000; ++i)
{
for (long long j = 0; j < 200000; ++j)
{
k = k + i - j;
}
}
mDummy = k;
}
主要.cpp
#include "algorithm.h"
#include <QtCore/QCoreApplication>
#include <QtConcurrent/QtConcurrent>
#include <vector>
#include <fstream>
#include <QFuture>
#include <memory>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
std::ofstream logFile;
logFile.open("AlgorithmLog.log", std::ios::trunc | std::ios::out);
if (!logFile.is_open())
{
return 1;
}
for (int i = 1; i < 8; i++)
{
int cores = i;
logFile << "Start: cores = " << cores << " " << QDateTime::currentDateTime().toString(Qt::ISODate).toLatin1().data() << "\n";
std::vector<std::unique_ptr<Algorithm>> cvAlgorithmRuns;
for (int j = 0; j < cores; ++j)
cvAlgorithmRuns.push_back(std::unique_ptr<Algorithm>(new Algorithm()));
QFuture<void> assyncCalls = QtConcurrent::map(cvAlgorithmRuns, [](std::unique_ptr<Algorithm>& x) { x->runAlgorithm(); });
assyncCalls.waitForFinished();
logFile << "End: " << QDateTime::currentDateTime().toString(Qt::ISODate).toLatin1().data() << "\n";
logFile.flush();
}
logFile.close();
return a.exec();
}
当我在我的笔记本电脑上运行它时(我使用的是 VS2015、x64、Qt 5.9.0、8 个逻辑处理器)我得到:
Start: cores = 1 2018-06-28T10:48:30 End: 2018-06-28T10:48:44
Start: cores = 2 2018-06-28T10:48:44 End: 2018-06-28T10:48:58
Start: cores = 3 2018-06-28T10:48:58 End: 2018-06-28T10:49:13
Start: cores = 4 2018-06-28T10:49:13 End: 2018-06-28T10:49:28
Start: cores = 5 2018-06-28T10:49:28 End: 2018-06-28T10:49:43
Start: cores = 6 2018-06-28T10:49:43 End: 2018-06-28T10:49:58
Start: cores = 7 2018-06-28T10:49:58 End: 2018-06-28T10:50:13
这是有道理的:无论我使用 1 个核心还是 7 个核心,所有步骤的运行时间都相同(14 到 15 秒之间)。
但是当我将 algoritm.h 中的行从:
protected:
long mDummy;
到:
protected:
double mDummy;
我得到这些结果:
Start: cores = 1 2018-06-28T10:52:30 End: 2018-06-28T10:52:44
Start: cores = 2 2018-06-28T10:52:44 End: 2018-06-28T10:52:59
Start: cores = 3 2018-06-28T10:52:59 End: 2018-06-28T10:53:15
Start: cores = 4 2018-06-28T10:53:15 End: 2018-06-28T10:53:32
Start: cores = 5 2018-06-28T10:53:32 End: 2018-06-28T10:53:53
Start: cores = 6 2018-06-28T10:53:53 End: 2018-06-28T10:54:14
Start: cores = 7 2018-06-28T10:54:14 End: 2018-06-28T10:54:38
在这里,我从 1 个内核的 14 秒运行时间开始,但使用 7 个内核时运行时间增加到 24 秒。
谁能解释为什么在第二次运行时使用多核时运行时间会增加?
最佳答案
我认为问题出在@Aconcagua 建议的 FPU 的实际数量上。“逻辑处理器”又名“超线程”与拥有两倍的内核不同。
超线程中的 8 个核心仍然是 4 个“真正的”核心。如果你仔细观察你的计时,你会发现执行时间几乎相同,直到你使用超过 4 个线程。当您使用超过 4 个线程时,您可能会开始耗尽 FPU。
但是,为了更好地理解这个问题,我建议您查看生成的实际汇编 代码。
当我们想要衡量原始性能时,我们必须记住,我们的 C++ 代码只是一个更高级别的表示,实际的可执行文件可能与我们预期的完全不同。
编译器会执行优化,CPU 会乱序执行,等等......
因此,首先我会建议在您的循环中避免使用常量限制。根据具体情况,编译器可能会展开循环,甚至用其计算结果完全替换。
举个例子,代码:
int main()
{
int z = 0;
for(int k=0; k < 1000; k++)
z += k;
return z;
}
由 GCC 8.1 编译并优化 -O2 为:
main:
mov eax, 499500
ret
如您所见,循环刚刚消失了!
编译器将其替换为实际的最终结果。
使用这样的示例来衡量性能是危险的。对于上面的示例,迭代 1000 次或 80000 次完全相同,因为在这两种情况下循环都被替换为常量(当然,如果您溢出了循环变量,编译器将无法再替换它)。
MSVC 没有那么激进,但除非您查看汇编代码,否则您永远不知道优化器到底做了什么。
查看生成的汇编代码的问题在于它可能非常庞大...
解决这个问题的一个简单方法是使用很棒的 compiler explorer .只需输入您的 C/C++ 代码,选择您要使用的编译器并查看结果。
现在,回到您的代码,我使用适用于 x86_64 的 MSVC2015 通过编译器资源管理器对其进行了测试。
没有优化它们的汇编代码看起来几乎相同,除了最后的内部转换为 double (cvtsi2sd)。
但是,当我们启用优化(这是在 Release模式下编译时的默认设置)时,事情开始变得有趣。
编译标志位-O2,当mDummy为long变量(32位)时产生的汇编代码为:
Algorithm::runAlgorithm, COMDAT PROC
xor r8d, r8d
mov r9d, r8d
npad 10
$LL4@runAlgorit:
mov rax, r9
mov edx, 100000 ; 000186a0H
npad 8
$LL7@runAlgorit:
dec r8
add r8, rax
add rax, -4
sub rdx, 1
jne SHORT $LL7@runAlgorit
add r9, 2
cmp r9, 400000 ; 00061a80H
jl SHORT $LL4@runAlgorit
mov DWORD PTR [rcx], r8d
ret 0
Algorithm::runAlgorithm ENDP
当 mDummy 为 float 时结束:
Algorithm::runAlgorithm, COMDAT PROC
mov QWORD PTR [rsp+8], rbx
mov QWORD PTR [rsp+16], rdi
xor r10d, r10d
xor r8d, r8d
$LL4@runAlgorit:
xor edx, edx
xor r11d, r11d
xor ebx, ebx
mov r9, r8
xor edi, edi
npad 4
$LL7@runAlgorit:
add r11, -3
add r10, r9
mov rax, r8
sub r9, 4
sub rax, rdx
dec rax
add rdi, rax
mov rax, r8
sub rax, rdx
add rax, -2
add rbx, rax
mov rax, r8
sub rax, rdx
add rdx, 4
add r11, rax
cmp rdx, 200000 ; 00030d40H
jl SHORT $LL7@runAlgorit
lea rax, QWORD PTR [r11+rbx]
inc r8
add rax, rdi
add r10, rax
cmp r8, 200000 ; 00030d40H
jl SHORT $LL4@runAlgorit
mov rbx, QWORD PTR [rsp+8]
xorps xmm0, xmm0
mov rdi, QWORD PTR [rsp+16]
cvtsi2ss xmm0, r10
movss DWORD PTR [rcx], xmm0
ret 0
Algorithm::runAlgorithm ENDP
无需详细了解这两种代码的工作原理或优化器为何在这两种情况下表现不同,我们可以清楚地看到一些差异。
特别是第二个版本(mDummy 为 float 的版本):
所以除了超线程问题,第二个版本更容易产生缓存未命中,并且由于缓存是共享的,这也会影响最终的执行时间。
此外,turbo boost 等功能也可能发挥作用。您的 CPU 在承受压力时可能会降速,从而导致整体执行时间增加。
作为记录,这是打开优化后 clang 产生的结果:
Algorithm::runAlgorithm(): # @Algorithm::runAlgorithm()
mov dword ptr [rdi], 0
ret
困惑?好吧……没有人在其他地方使用 mDummy,所以 clang 决定完全删除整个东西……:)
关于c++ - QtConcurrent 为多核提供更长的运行时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51079939/
人们在运行TwistedWeb服务器时使用哪些技术来利用多个处理器/内核?有推荐的方法吗? 我基于twisted.web的Web服务在Amazon EC2实例上运行,该实例通常具有多个CPU核心(8、
multicore 库中是否有类似 sapply 的东西?还是我必须 unlist(mclapply(..)) 才能实现这一点? 如果它不存在:推理是什么? 提前致谢,如果这是一个愚蠢的问题,我们深表
ZeroMQ 用于接收输入参数.. def server(): rep = context.socket(zmq.REP) rep.bind('tcp://*:{}'.format(P
我有一大组标量值分布在 3D 网格上(每个顶点一个值。) 我的目标是展示: 网格中值大于阈值的所有点。 并将连接的点分组(以简化显示。) 所以我的基本解决方案是: 找到通过阈值测试的点 对于每个没有被
作者:小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功、JAVA底层、面试、职业成长相关资料等更多精彩文章在公众号「 小牛呼噜噜 」 。 大家好,我是呼噜噜,
有没有办法让 J 使用多个核心?我认为 APL/J 的部分好处是语言结构很适合并行解决方案。 查看我的 CPU 使用率(我在 OSX 上),显然只有一个处理器在使用。 我有一个很重的函数 f 作用在一
多核处理器如何处理中断。 我知道单核处理器如何处理中断。 我也知道不同类型的中断。 我想知道多核处理器如何处理硬件、程序、cpu时序和输入/输出中断 最佳答案 这应该被视为 other answer
很长一段时间以来,我一直将 LLVM 视为我目前正在实现的语言的新后端。它似乎具有良好的性能,相当高级的生成 API,足够的低级支持来优化奇特的优化。此外,虽然我自己没有检查过,但苹果似乎已经成功地演
我最近开始研究低级OS编程。我(非常缓慢)目前正在研究两本较旧的书,即XINU和Build Your Own 32 Bit OS,以及上一个问题How to get started in operat
我正在阅读对新英特尔凌动 330 的评论,他们指出任务管理器显示 4 个内核 - 两个物理内核,另外还有两个由超线程模拟。 假设您有一个包含两个线程的程序。还假设这些是在 PC 上执行任何工作的唯一线
我不知道如何在 C++ 中进行线程化,我不仅不想知道,而且有没有一种方法可以将线程强制到不同的核心上?另外,我如何才能知道用户拥有多少个内核? 最佳答案 将线程绑定(bind)到任意 CPU 称为设置
如果需要在多核处理器机器的多个内核上并行执行,Linux 内核是否会同时执行多个上下文切换?有引用吗? 最佳答案 是的,你是对的。在 SMP 系统上,多个上下文切换同时发生。每个核心都可以独立进行上下
与进程相比,线程更不可能从多核处理器中获益,这是真的吗?换句话说,内核会决定在单核而不是多核上执行线程吗? 我说的是属于同一进程的线程。 最佳答案 我不知道(各种)Linux 调度程序如何处理这个问题
我需要一些帮助来决定在单个 Solr 实例中创建单个索引还是在单个 Solr 实例中创建多个核心,每个核心为一个索引提供服务。 我的理解是,solr 中的单个索引通常用于索引一种类型的文档。当您有不同
NGINX 或 Apache 是否受益于具有以下任一项的服务器: 多核,或者 多个处理器? 如果是,为什么? 最佳答案 使用多个 CPU/CPU 内核使服务器应用程序有机会并行处理多个客户端连接(和请
我正在为我的爱好操作系统开发 CPU 检测和一般环境检测代码。是否存在需要多次调用 CPUID 的情况?也就是说如果系统有多个核心,操作系统是否需要在每个核心上调用CPUID? NUMA 也是如此。
我有一些关于多核 CPU 或多处理器系统中使用的高速缓存存储器的问题。 (虽然与编程没有直接关系,但当一个人为多核处理器/多处理器系统编写软件时,它会产生很多影响,因此在此询问!) 在多处理器系统或多
所以,我一直在使用 opencv 开发实时跟踪系统。几天前,我不得不开始使用 directshow(这对我来说是全新的),因为我需要网络摄像头的更高分辨率。分辨率越高,CPU 使用率就越高。仅使用没有
我经常听说其他语言被提升为更适合多核/并发编程,例如Clojure、Scala、Erlang 等,但我有点困惑为什么我需要担心多核问题,Java/.NET VM 不应该自动处理吗?如果没有,背后的原因
假设 x86 多核 PC 架构... 假设有 2 个内核(能够执行 2 个单独的指令流),并且 CPU 和 RAM 之间的接口(interface)是内存总线。 调度在 2 个不同内核上的 2 条指令
我是一名优秀的程序员,十分优秀!