Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 何时以及如何正确使用循环优化和转换技术_Java_C_Optimization_Loops - Fatal编程技术网

Java 何时以及如何正确使用循环优化和转换技术

Java 何时以及如何正确使用循环优化和转换技术,java,c,optimization,loops,Java,C,Optimization,Loops,首先,我想知道循环优化和转换之间的根本区别是什么 C中的一个简单循环如下所示: for (i = 0; i < N; i++) { a[i] = b[i]*c[i]; } (i=0;i

首先,我想知道循环优化和转换之间的根本区别是什么

C中的一个简单循环如下所示:

for (i = 0; i < N; i++)
{
a[i] = b[i]*c[i];
}
(i=0;i { a[i]=b[i]*c[i]; } 但我们可以将其展开到:

for (i = 0; i < N/2; i++) 
{
a[i*2] = b[i*2]*c[i*2];
a[i*2 + 1] = b[i*2 + 1]*c[i*2 + 1];
}
(i=0;i { a[i*2]=b[i*2]*c[i*2]; a[i*2+1]=b[i*2+1]*c[i*2+1]; } 但是我们可以进一步展开它。但是我们可以展开它的极限是什么,我们如何找到它呢


还有很多技术,如循环耕作、循环分配等,如何确定何时使用合适的技术。

这似乎与您的问题有点离题,但我不得不强调这一点的重要性

关键是要编写正确的代码,并使您的代码按照要求运行,而不必担心微观优化。
如果以后您发现您的程序缺乏性能,那么您可以配置文件您的应用程序可以找到问题区域,然后尝试对其进行优化。

请记住,正如一位智者所说,只有10%的代码运行了90%的应用程序运行时间。诀窍是通过分析识别代码,然后尝试对其进行优化。

考虑到您的第一次优化尝试在50%的情况下都是错误的,我真的不会这么做尝试更复杂的方法(尝试任何奇数)

另外,不要将指数相乘,只需将2添加到i并再次循环到N即可避免不必要的移位(只要保持2的幂次,效果很小,但仍然如此)


总而言之:您创建了错误的、比编译器所能做的还要慢的代码-这就是我认为您不应该做这些事情的完美例子。

我假设OP已经分析了他/她的代码,并且发现这段代码实际上很重要,并实际回答了以下问题:-):

编译器将根据对代码和处理器体系结构的了解,尝试做出循环展开决策

在加快速度方面

  • 正如有人指出的,展开确实减少了循环终止条件和跳跃的数量
  • 根据体系结构,硬件还可以支持在不添加额外指令的情况下对靠近内存位置的位置(例如,mov eax、[ebx+4])进行索引的有效方法(这可能会扩展到更多微操作-不确定)
  • 大多数现代处理器使用无序执行来寻找指令级并行性。这是很难做到的,当下一个N指令在多个条件跳转之后(即,硬件需要能够丢弃可变级别的推测)。
    • 有更多的机会提前对内存操作进行重新排序,从而隐藏数据获取延迟
    • 代码矢量化(例如,转换为SSE/AVX)也可能发生,这在某些情况下允许并行执行代码。这也是展开的一种形式
在决定何时停止展开时:

  • 展开会增加代码大小。编译器知道,超过指令代码缓存大小(所有现代处理器)、跟踪缓存(P4)、循环缓冲缓存(Core2/Nehalem/SandyBridge)、微操作缓存(SandyBridge)等都会受到惩罚。理想情况下,它使用静态成本效益试探法(特定代码和体系结构的函数)确定哪一级别的展开将产生最佳的整体净性能。根据编译器的不同,启发式可能会有所不同(我经常发现自己调整一下会很好)。
    • 通常,如果循环包含大量代码,则展开的可能性较小,因为循环成本已摊销,有大量ILP可用,展开的代码膨胀成本过高。对于较小的代码段,循环可能会展开,因为成本可能较低。展开的实际数量将取决于体系结构、编译器试探法和代码的具体情况,并且将是编译器认为最佳的(可能不是:-))
关于何时应该进行这些优化:

  • 当你认为编译器做的事情不对的时候。编译器可能不够复杂(或不够最新),无法以最佳方式使用您正在处理的体系结构知识

  • 很可能,试探法失败了(毕竟它们只是试探法)。通常,如果您知道这段代码非常重要,请尝试展开它,如果它提高了性能,请保留它,否则将其丢弃。另外,只有当您大致拥有整个系统时,才可以这样做,因为当您的代码工作集为20k时,可能有益的是,当您的代码工作集为31k时,可能不会有益


为什么不让编译器为您执行此操作?确保启用了优化,然后走出去做一些有趣的事情。编译器是如何决定的……出于好奇。@pmg这不是我的,它来自Wayner Wolf的书,这是一本非常好的书。如果你为嵌入式或实时系统开发,这才是真正值得做的,每一纳秒都很重要。否则,展开的代码可能会在具有特定编译器的特定系统上运行得稍快一些,但当编译器找到更好的方法时,其他地方的运行会变得更糟。@pmg您要判断谁。?纽瓦兹,你说的不对,阿尔索威尔,那么你完全错了,如果我可以的话,我会对你的答案投反对票,优化技术来自韦纳·沃尔夫的书,而且比原著花费的时间更少(它经过测试)。如果您有疑问,请阅读有关循环展开的内容first@sum2000你试过密码了吗?说它是正确的,因为它是有人写的