【问题标题】:Why is for-in slower than while in swift debugging mode?为什么 for-in 比在快速调试模式下慢?
【发布时间】:2021-07-05 08:01:09
【问题描述】:

为什么 for-in 比在 swift 调试模式下慢? 如果您认为,是的,它是在 no optimization 中运行的。

⬇️下面的代码,时间是for-in和while的比较,没有优化

49999995000000 for-in -- 时间 = 3.3352

4999999950000000 而 -- 时间 = 0.3613

⬇️但是,如果使用速度优化

49999995000000 for-in -- 时间 = 0.0037

49999995000000 而 -- 时间 = 0.0035

我想知道“为什么 for-in 比没有优化时慢?为什么 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)
}

【问题讨论】:

    标签: swift for-loop


    【解决方案1】:

    从 Swift 的角度来看,您的 for 循环实际上转换为如下内容:

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

    请注意,在范围的迭代器上对 next 的调用很多,它有自己的状态需要跟踪,IndexingIterator.next 调用了一堆协议方法,调度也需要一些时间必须查找见证表。看看调用Iterator.next 会变成here

    如果您处于调试模式,则不会进行任何优化。

    将其与您的 while 循环进行比较,该循环基本上将某些内容设置为 0,比较,执行循环中的内容,将其加 1,然后重复。显然,这比调用所有这些方法要简单得多。

    但是,如果您启用优化,编译器可以看到 for 循环正在执行 while 循环所做的事情。


    因为我觉得它很有趣,所以我做了一个循环的时间简介,例如:

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

    80% 的时间都花在next() 上,看看它做了多少事情!我的截图甚至不能包含所有内容。字符串拼接只占6%左右(截图中没有)。

    【讨论】:

    • 多亏了你,我现在可以学习 makeIterator() 甚至你所说的非常重要的虚方法概念。非常感谢!
    • 天哪!我不知道那个很酷的时间分析器。我应该学习那个。谢谢你。我真的很想看到那个。这对我很有用!非常感谢!
    • 您可能还会发现运行swiftc -emit-sil -O &lt;file.swift&gt; 很有用。至少在 Swift 中级语言的级别上,这会排除 Swift “真正”在做的事情。 Clang 通常会进一步优化这些东西,但是学习阅读 SIL 输出是学习优化的一项很棒的技能。您可能也有兴趣探索(0..&lt;10000000).reduce(0, +) 在未优化与优化之间的更大差异。
    • @RobNapier 哦,谢谢!其实我知道 SIL,但多亏了你,不知道这个概念的人可以理解“什么是 SIL?为什么 SIL 在编译时有用?”即使你举了一些有趣的例子。太感谢了!我将不得不更多地学习 SIL。
    • @RobNapier 我正在使用 Godbolt 来比较汇编代码。我看到优化后的版本去掉了所有的IndexingIterators,否则无法读取asm。我从来不知道 SIL 是一回事!谢谢你也告诉我!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-31
    • 2019-10-31
    • 1970-01-01
    • 2022-06-12
    • 1970-01-01
    • 2020-02-16
    • 1970-01-01
    相关资源
    最近更新 更多