为什么在Swift调试模式下,for-in循环比while循环慢?

5
为什么在Swift调试模式下,for-in循环比while循环慢? 如果您认为是运行在“无优化”模式下的话,是这样的。
下面的代码比较了for-in和while在“无优化”模式下的执行时间:
49999995000000 for-in -- 时间 = 3.3352
4999999950000000 while -- 时间 = 0.3613
但是,如果使用“加速优化”,则结果如下:
49999995000000 for-in -- 时间 = 0.0037
49999995000000 while -- 时间 = 0.0035
我想知道,“为什么在无优化模式下for-in比while慢?而在优化模式下它们为什么会快呢?”
import Foundation

func processTime(_ title: String, blockFunction: () -> ()) {
    print()
    let startTime = CFAbsoluteTimeGetCurrent()
    blockFunction()
    let processTime = CFAbsoluteTimeGetCurrent() - startTime
    print(title, " -- time = \(String(format : "%.4f",processTime))")
}

processTime("for-in") {
    var sum = 0
    for i in 0..<10000000 {
        sum += i
    }
    print(sum)
}

processTime("while") {
    var sum = 0
    var i = 0
    while i<10000000 {
        sum += i
        i += 1
    }
    print(sum)
}

1个回答

7

从 Swift 的角度来看,你的 for 循环实际上会被翻译成这样:

let range = 0..<10000000
var iterator = range.makeIterator()
while let next = iterator.next() {
    ...
}

请注意,这是对范围迭代器上的许多next调用,它有自己的状态需要跟踪,并且IndexingIterator.next调用一堆协议方法,分派需要一些时间,因为它必须查找见证表。在这里可以看到Iterator.next将要进行的确切调用。
如果您处于调试模式,则不会对其进行任何优化。
与您的while循环相比,它基本上是将某些内容设置为0,进行比较,执行循环中的操作,将其加1,然后重复执行。显然,这比调用所有这些方法要简单得多。
但是,如果启用了优化,编译器可以看到for循环正在执行while循环所做的事情。

因为我觉得很有趣,所以我做了一个类似于以下的循环时间分析:

var s = ""
for i in 0...10000000 {
    s += "\(i)"
}

enter image description here

80%的时间都花费在next()上,看看它做了多少事情!我的屏幕截图甚至无法包含所有内容。字符串连接仅占约6%(不在截图中)。


1
我的天啊!我不知道那个很酷的时间分析器。我应该学一下。谢谢你。我真的很想看看它。这对我来说非常有用!非常感谢你! - HyunSu
1
您可能会发现运行 swiftc -emit-sil -O <file.swift> 很有用。这将转储出 Swift 在 Swift 中间语言级别上的“真正”操作。Clang 通常会进一步优化这些内容,但学习阅读 SIL 输出是学习优化的重要技能。您可能还对探索非优化与优化后的 (0..<10000000).reduce(0, +) 的巨大差异感兴趣。 - Rob Napier
1
@RobNapier 哦,谢谢你!!其实我知道SIL,但是多亏了你,那些不知道这个概念的人可以理解“什么是SIL?为什么在编译时使用SIL很有用?”甚至你还给出了一些有趣的例子。非常感谢!我将不得不更多地学习SIL。 - HyunSu
1
@RobNapier 我在使用godbolt比较汇编代码。我看到优化版本摆脱了所有的“IndexingIterator”,但是其他方面我无法阅读汇编代码。我从未知道SIL是一种东西!谢谢你告诉我这个! - Sweeper
@Sweeper 你好,我的教授,你能给我关于我的新问题的信息吗?https://stackoverflow.com/questions/67032783/why-is-indexingiterator-next-using-dynamic-dispatch - HyunSu
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接