- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
这是 DV 的典型问题,所以在发布之前我犹豫了(很多)......
我知道这个question被标记为重复,但我的测试(如果它们好:它们好吗?这是问题的一部分)往往表明情况并非如此。
一开始,我做了一些测试,比较了 for 循环和 while 循环。
这表明 for 循环更好。
但更进一步,暂时或暂时不是重点:区别在于:
for (int l = 0; l < loops;l++) {
或
for (int l = 0; l != loops;l++) {
如果您运行它(在 Windows 10、Visual Studio 2017 版本下),您会发现第一个比第二个快两倍以上。
很难(对于我这样的新手)理解编译器是否出于某种原因能够优化更多的一个或另一个。但是……
为什么?
完整代码如下:
对于“<”循环:
int forloop_inf(int loops, int iterations)
{
int n = 0;
int x = n;
for (int l = 0; l < loops;l++) {
for (int i = 0; i < iterations;i++) {
n++;
x += n;
}
}
return x;
}
对于 '!=' 循环:
int forloop_diff(int loops, int iterations)
{
int n = 0;
int x = n;
for (int l = 0; l != loops;l++) {
for (int i = 0; i != iterations;i++) {
n++;
x += n;
}
}
return x;
}
在这两种情况下,内部计算都在这里,以避免编译器跳过所有循环。
分别由以下人员调用:
printf("for loop inf %f\n", monitor_int(loops, iterations, forloop_inf, &result));
printf("%d\n", result);
和
printf("for loop diff %f\n", monitor_int(loops, iterations, forloop_diff, &result));
printf("%d\n", result);
其中循环次数 = 10 * 1000,迭代次数 = 1000 * 1000。
monitor_int 在哪里:
double monitor_int(int loops, int iterations, int(*func)(int, int), int *result)
{
clock_t start = clock();
*result = func(loops, iterations);
clock_t stop = clock();
return (double)(stop - start) / CLOCKS_PER_SEC;
}
以秒为单位的结果是:
for loop inf 2.227 seconds
for loop diff 4.558 seconds
因此,即使与循环本身相比,所有内容的重要性都与循环内部完成的事情的权重有关,为什么会有这样的差异?
编辑:
你可以找到here审查了完整的源代码,以便多次以随机顺序调用函数。
对应的反汇编为here (通过 dumpbin/DISASM CPerf2.exe 获得)。
运行它,我现在得到:
我不知道如何在Visual Studio中设置O3,编译命令行如下:
/permissive- /Yu"stdafx.h" /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"x64\Release\vc141.pdb" /Zc:inline /fp:precise /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /FC /Fa"x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Ot /Fp"x64\Release\CPerf2.pch" /diagnostics:classic
循环的代码在上面,这里是随机运行的方式:
typedef int(loop_signature)(int, int);
void loops_compare()
{
int loops = 1 * 100;
int iterations = 1000 * 1000;
int result;
loop_signature *functions[2] = {
forloop_diff,
forloop_inf
};
int n_rand = 1000;
int n[2] = { 0, 0 };
double cum[2] = { 0.0, 0.0 };
for (int i = 0; i < n_rand;i++) {
int pick = rand() % 2;
loop_signature *fun = functions[pick];
double time = monitor(loops, iterations, fun, &result);
n[pick]++;
cum[pick] += time;
}
printf("'!=' %f (%d) / '<' %f (%d)\n", cum[0] / (double)n[0], n[0], cum[1] / (double)n[1], n[1]);
}
和反汇编(仅循环功能,但不确定它是否是上面链接的良好摘录):
?forloop_inf@@YAHHH@Z:
0000000140001000: 48 83 EC 08 sub rsp,8
0000000140001004: 45 33 C0 xor r8d,r8d
0000000140001007: 45 33 D2 xor r10d,r10d
000000014000100A: 44 8B DA mov r11d,edx
000000014000100D: 85 C9 test ecx,ecx
000000014000100F: 7E 6F jle 0000000140001080
0000000140001011: 48 89 1C 24 mov qword ptr [rsp],rbx
0000000140001015: 8B D9 mov ebx,ecx
0000000140001017: 66 0F 1F 84 00 00 nop word ptr [rax+rax]
00 00 00
0000000140001020: 45 33 C9 xor r9d,r9d
0000000140001023: 33 D2 xor edx,edx
0000000140001025: 33 C0 xor eax,eax
0000000140001027: 41 83 FB 02 cmp r11d,2
000000014000102B: 7C 29 jl 0000000140001056
000000014000102D: 41 8D 43 FE lea eax,[r11-2]
0000000140001031: D1 E8 shr eax,1
0000000140001033: FF C0 inc eax
0000000140001035: 8B C8 mov ecx,eax
0000000140001037: 03 C0 add eax,eax
0000000140001039: 0F 1F 80 00 00 00 nop dword ptr [rax]
00
0000000140001040: 41 FF C1 inc r9d
0000000140001043: 83 C2 02 add edx,2
0000000140001046: 45 03 C8 add r9d,r8d
0000000140001049: 41 03 D0 add edx,r8d
000000014000104C: 41 83 C0 02 add r8d,2
0000000140001050: 48 83 E9 01 sub rcx,1
0000000140001054: 75 EA jne 0000000140001040
0000000140001056: 41 3B C3 cmp eax,r11d
0000000140001059: 7D 06 jge 0000000140001061
000000014000105B: 41 FF C2 inc r10d
000000014000105E: 45 03 D0 add r10d,r8d
0000000140001061: 42 8D 0C 0A lea ecx,[rdx+r9]
0000000140001065: 44 03 D1 add r10d,ecx
0000000140001068: 41 8D 48 01 lea ecx,[r8+1]
000000014000106C: 41 3B C3 cmp eax,r11d
000000014000106F: 41 0F 4D C8 cmovge ecx,r8d
0000000140001073: 44 8B C1 mov r8d,ecx
0000000140001076: 48 83 EB 01 sub rbx,1
000000014000107A: 75 A4 jne 0000000140001020
000000014000107C: 48 8B 1C 24 mov rbx,qword ptr [rsp]
0000000140001080: 41 8B C2 mov eax,r10d
0000000140001083: 48 83 C4 08 add rsp,8
0000000140001087: C3 ret
0000000140001088: CC CC CC CC CC CC CC CC ÌÌÌÌÌÌÌÌ
?forloop_diff@@YAHHH@Z:
0000000140001090: 45 33 C0 xor r8d,r8d
0000000140001093: 41 8B C0 mov eax,r8d
0000000140001096: 85 C9 test ecx,ecx
0000000140001098: 74 28 je 00000001400010C2
000000014000109A: 44 8B C9 mov r9d,ecx
000000014000109D: 0F 1F 00 nop dword ptr [rax]
00000001400010A0: 85 D2 test edx,edx
00000001400010A2: 74 18 je 00000001400010BC
00000001400010A4: 8B CA mov ecx,edx
00000001400010A6: 66 66 0F 1F 84 00 nop word ptr [rax+rax]
00 00 00 00
00000001400010B0: 41 FF C0 inc r8d
00000001400010B3: 41 03 C0 add eax,r8d
00000001400010B6: 48 83 E9 01 sub rcx,1
00000001400010BA: 75 F4 jne 00000001400010B0
00000001400010BC: 49 83 E9 01 sub r9,1
00000001400010C0: 75 DE jne 00000001400010A0
00000001400010C2: C3 ret
00000001400010C3: CC CC CC CC CC CC CC CC CC CC CC CC CC ÌÌÌÌÌÌÌÌÌÌÌÌÌ
再次编辑:
让我感到意外的还有以下几点:
最佳答案
为了进行适当的基准测试,以随机顺序多次运行函数非常重要。
typedef int(signature)(int, int);
...
int main() {
int loops, iterations, runs;
fprintf(stderr, "Loops: ");
scanf("%d", &loops);
fprintf(stderr, "Iterations: ");
scanf("%d", &iterations);
fprintf(stderr, "Runs: ");
scanf("%d", &runs);
fprintf(stderr, "Running for %d loops and %d iterations %d times.\n", loops, iterations, runs);
signature *functions[2] = {
forloop_inf,
forloop_diff
};
int result = functions[0](loops, iterations);
for( int i = 0; i < runs; i++ ) {
int pick = rand() % 2;
signature *function = functions[pick];
int new_result;
printf("%d %f\n", pick, monitor_int(loops, iterations, function, &new_result));
if( result != new_result ) {
fprintf(stderr, "got %d expected %d\n", new_result, result);
}
}
}
有了这个,我们可以随机运行 1000 次并找到平均时间。
在启用优化的情况下进行基准测试也很重要。询问未优化代码的运行速度有多快没有多大意义。我会尝试 -O2
和 -O3
.
我的发现是 Apple LLVM version 8.0.0 (clang-800.0.42.1)
在 -O2
处执行 10000 次循环和 1000000 次迭代forloop_inf
确实比 forloop_diff
快了大约 50% .
forloop_inf: 0.000009
forloop_diff: 0.000014
查看the generated assembly code for -O2与 clang -O2 -S -mllvm --x86-asm-syntax=intel test.c
我可以看到 many differences between the two implementations .也许了解汇编的人可以告诉我们原因。
但是在 -O3
性能差异不再明显。
forloop_inf: 0.000002
forloop_diff: 0.000002
这是因为at -O3
they are almost exactly the same .一个正在使用 je
一个正在使用 jle
.就是这样。
总而言之,当进行基准测试时......
最重要的是。
i < max
比 i != max
更安全因为如果 i
它仍然会终止以某种方式跳过max
.
正如所展示的那样,启用优化后,它们都非常快,即使没有完全优化,它们也可以在 0.000009 秒内完成 10,000,000,000 次迭代。 i < max
或 i != max
不太可能成为性能瓶颈,无论您做什么 100 亿次都是。
但是i != max
可能会导致错误。
关于c - 在 C 中,(真的) '<' 比 '!=' 快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50591174/
这看起来很基础,但我想不通。是否有一种简单的 CSS 唯一方法可以使 cssa 真正快速淡入并缓慢淡出。这是为了改变多个 div 的颜色。大约 0.5 秒的缓入和 2 秒的缓出。 谢谢! 最佳答案 你
我一直在用各种语言和实现实现相同的代码(在 Blackjack 中发牌而不爆牌的方法的数量)。我注意到的一个奇怪之处是,Python 在 C 中调用分区函数的实现实际上比用 C 编写的整个程序快一点。
如果我没看错,/ 意味着它右边的节点必须是左边节点的直接子节点,例如/ul/li 返回 li 项,它们是作为文档根的 ul 项的直接子项。 //ul//li 返回 li 项,它们是文档中某处任何 ul
如何随机更新一个表。所以你给一列一个随机值。并且该列(例如“顶部”)是唯一的。如果您在数字 10 到 20 之间进行选择,并且您有 10 行,那么您就不能有未使用的数字。如果你有 Test table
这在一小部分是一个问题(因为我不明白为什么它会有所不同),在很大程度上是一篇希望能帮助其他一些可怜的程序员的帖子。 我有一个代码库,是我大约 5-7 年前第一次开始 Android 编程时编写的,它具
我正在尝试过滤关系表以获得满足两个条件的表子集(即:我想要 color_ids 为 1 或 2 的条目的所有 ID)。这是一张结实的 table ,所以我正在尝试尽可能多地进行优化。 我想知道是否有人
在上一篇《聊聊PHP中require_once()函数为什么不好用》中给大家介绍了PHP中require_once()为什么不好用的原因,感兴趣的朋友可以去阅读了解一下~ 那么本文将给大家介绍PH
很难说出这里问的是什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或言辞激烈,无法以目前的形式合理回答。如需帮助澄清此问题以便可以重新打开,visit the help center . 10年前关
有没有办法提高glReadPixels的速度?目前我做: Gdx.gl.glReadPixels(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeig
通常,我以函数形式`:=`()来计算data.table中的多列,认为这是最有效的方法。但是我最近发现它比简单地重复使用:=慢。至少在我的电脑上。 我猜想:=的功能形式可能会产生一些开销,但这是它变慢
我的问题是针对 Windows 环境中多线程的性能问题。 在测试我的代码后,我得到的结果是增加线程数不会提高并行计算的性能,并且在经过一些计数后变得更少。到底是怎么回事?是否可以找出最佳线程数的公式:
我看到很少有相同问题的主题,但我仍然无法解决我的问题。这是我的代码 - 使用 XOR 加密的 C 套接字编程 当服务器和客户端连接时:- 用户发送消息,例如:你好- 服务器响应,例如:(服务器):你好
我正在定义继承自 Shape 类并实现“几何”属性的形状。 这是一个例子: public class Landmark : Shape { public override bool IsInB
相同代码在 Android(1Ghz Snapdragon)上的执行速度比我在 3.3 Ghz Core 2 Duo 的 PC(在桌面应用程序中)快 2 倍(PC 的类被复制到 Android 项目)
我需要将一个值与一组数组进行比较。但是,我需要比较 foreach 中的多个值。如果使用 in_array,它可能会很慢,真的很慢。有没有更快的选择?我当前的代码是 foreach($a as $b)
这个问题在这里已经有了答案: How do I write a correct micro-benchmark in Java? (11 个答案) 关闭 9 年前。 今天我做了一个简单的测试来比较
如果比较不应该以这种方式进行,我深表歉意。我是编程新手,只是很好奇为什么会这样。 我有一个包含词嵌入的大型二进制文件 (4.5gb)。每行都有一个单词,后面跟着它的嵌入,它由 300 个浮点值组成。我
我经历了几个不同的四元数乘法实现,但我很惊讶地发现引用实现是迄今为止我最快的实现。这是有问题的实现: inline static quat multiply(const quat& lhs, cons
我写了一个简单的例子,估计调用虚函数的平均时间,使用基类接口(interface)和dynamic_cast和调用非虚函数。这是它: #include #include #include #in
有没有人知道比“StackWalk”更好/更快的获取调用堆栈的方法?我还认为 stackwalk 在有很多变量的方法上也会变慢......(我想知道商业分析员是做什么的?)我在 Windows 上使用
我是一名优秀的程序员,十分优秀!