Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.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
Loops 深入理解循环(for、while、do-while、foreach、递归等)_Loops_Performance_Memory Management - Fatal编程技术网

Loops 深入理解循环(for、while、do-while、foreach、递归等)

Loops 深入理解循环(for、while、do-while、foreach、递归等),loops,performance,memory-management,Loops,Performance,Memory Management,如果给定某种情况,您可以对需要使用循环解决的特定事件或函数执行循环,您可以通过任何类型的循环来实现这些。我们如何根据每个循环的速度、效率和内存使用情况来确定它们之间的差异?例如,您有这些循环 for(int i=0;i<10;i++) { array[i] = i+1; } int i = 0; while(i<10) { array[i] = i+1; i++; } for(inti=0;i循环本身的名称给出了用法的概念 当您只需要执行一个操作时,不需要

如果给定某种情况,您可以对需要使用循环解决的特定事件或函数执行循环,您可以通过任何类型的循环来实现这些。我们如何根据每个循环的速度、效率和内存使用情况来确定它们之间的差异?例如,您有这些循环

for(int i=0;i<10;i++) {
    array[i] = i+1;
}

int i = 0;
while(i<10) {
    array[i] = i+1;
    i++;
}

for(inti=0;i循环本身的名称给出了用法的概念

当您只需要执行一个操作时,不需要询问任何问题,for循环就可以很好地执行


如果您在数据结构上进行迭代,并且有一个约束,如中断条件或类似的情况,则应选择while或do-while循环。

这只是个人偏好和编码风格的问题-首选的样式也在很大程度上取决于您所用的编码语言

例如,在python中,执行上述循环的首选方法看起来有点像:

for i in range(0, 9):
    array[i] = i + 1
(事实上,在Python中,您可以在一行中完成上述操作:

array = range(1,10)
但这只是一个例子……)

在以上两种中,我更喜欢第一种


至于性能,您不太可能看到差异。

我将逐一解释每个循环情况

1.For loop:当您确定您执行了某些迭代次数时,请执行For循环

2.While循环:如果不确定迭代次数,则执行While循环或希望循环,直到条件为false

3.执行while:这与while循环相同,只是循环至少执行一次

话虽如此,为另一种情况编写一个循环也是可以的

4.递归:如果您正确理解递归,递归将导致优雅的解决方案。 递归比直接迭代慢一点


for、while和do-while之间没有性能差异。如果有的话,它们可以忽略不计。

好吧,这里很难解释循环背后的所有逻辑

为了优化循环,编译器将为您做一些令人惊奇的事情,因此无论您使用
while
还是
for
,这都无关紧要,因为编译器无论如何都会转换为assembler

为了更深入地理解,您应该学习一些汇编程序,然后学习基本处理器如何工作,如何读取指令以及如何处理指令

为了改进流水线,最好将具有相同变量的语句放在彼此远离的地方。这样,在计算一条语句时,如果下一条语句独立于第一条语句,处理器可以获取下一条语句并开始计算它

例如:

a=0;
b=3;
c=5;
m=8;
i=0;
while(i<10){
a=a+b*c;
b=b*10+a;
m=m*5;
i++;
}
因此,在计算
a
时,我们可以开始计算
m
i
。大多数情况下,编译器会检测到这一点并自动执行(称为代码重新排序)。有时对于小循环,编译器会根据需要将代码复制并粘贴到循环中,因为没有控制变量更快

我的建议是,让编译器关注这些事情,并关注您正在使用的算法的成本,最好将O(n!)减少到O(logn),而不是在循环内部进行微优化

根据修改的问题进行更新

好的,依赖项必须是写/写或读/写依赖项。如果是读/读依赖项,则没有问题(因为值不变)。请查看[Data dependency article]()

在您的示例中,这两个代码之间没有区别,
m
依赖于
c
b
,但这两个代码从未被写入,因此编译器在进入循环之前就知道它们的值。这称为读/读依赖项,而不是依赖项本身

如果你写过:

...
m=c+GetAvarage(a);
...
然后我们会有一个写/读依赖关系(我们必须在
a
中写入,然后从
a
中读取,所以我们必须等到
a
计算出来),您所做的优化会很好。

但是再一次,编译器为您和其他许多事情做这件事。很难说高级代码中的微优化会对汇编代码产生真正的影响,因为可能编译器已经在为您做这件事,或者可能正在为您重新排序代码,或者可能正在做一千件比w更好的事情我一眼就能想到

但不管怎样,只要知道地毯下的事情是如何运作的就好了:)

更新以添加一些链接 查看以下链接,进一步了解编译器可以做些什么来提高代码性能:


这当然取决于您使用的语言,但请记住,任何代码中最慢的部分都是编写代码的人,因此我建议您为每种情况选择一个标准并坚持执行,然后当您更新代码时,无需每次都考虑这一点

如果你想通过这样的方式节省开支,那么你要么已经在以接近100%的效率运行,要么可能在错误的地方寻找加快代码速度的方法?

在帕特森和轩尼诗的《计算机组织与设计:硬件/软件接口》一书中,作者将上述循环转换为汇编,两个循环在MIPS中具有相同的汇编代码

如果您的编译器在不同的汇编语句中编译两个循环,则会出现差异。如果两个循环的性能不相同,则会出现差异。

任何合适的编译器都会生成相同的代码

为了测试这一点,我创建了一个名为
loops-f.c
的文件:

void f(int array[])
{
    for(int i=0; i<10; i++) {
        array[i] = i+1;
    }
}
void g(int array[])
{
    int i = 0;
    while(i<10) {
        array[i] = i+1;
        i++;
    }
}
我将文件编译成汇编(
gcc-std=c99-S loops-f.c loops-g.c
),然后比较生成的汇编代码(
...
m=c+GetAvarage(a);
...
void f(int array[])
{
    for(int i=0; i<10; i++) {
        array[i] = i+1;
    }
}
void g(int array[])
{
    int i = 0;
    while(i<10) {
        array[i] = i+1;
        i++;
    }
}
--- loops-f.s   2010-08-06 10:57:11.377196516 +0300
+++ loops-g.s   2010-08-06 10:57:11.389197986 +0300
@@ -1,8 +1,8 @@
-   .file   "loops-f.c"
+   .file   "loops-g.c"
    .text
-.globl f
-   .type   f, @function
-f:
+.globl g
+   .type   g, @function
+g:
 .LFB0:
    .cfi_startproc
    pushq   %rbp
@@ -30,6 +30,6 @@
    ret
    .cfi_endproc
 .LFE0:
-   .size   f, .-f
+   .size   g, .-g
    .ident  "GCC: (GNU) 4.4.4 20100630 (Red Hat 4.4.4-10)"
    .section    .note.GNU-stack,"",@progbits