首页 > 解决方案 > 为什么 indexingIterator.next() 使用动态调度?

问题描述

为什么 for-in 比在快速调试模式下慢? 我写了这个。感谢那些回答我的人,我本可以学习SeqeunceIteratorProtocol.

所以我实现School了符合的自定义类型(下面的代码)Sequence。我检查了 Xcode-time 配置文件。

但我找不到任何协议见证 在此处输入图像描述

但如果只使用rangeand for-in,时间分析器显示 协议见证

在此处输入图像描述

为什么indexingIterator.next()使用动态方法而不是 in School?我认为即使struct符合protocol,如果变量struct类型使用方法protocol,该方法将是静态方法。如果我错了,你能告诉我哪里错了吗?

⬇️School代码

struct SchoolIterator: IteratorProtocol {
    
    private var schoolList: School
    var idx = 0
    init(_ school: School) {
        self.schoolList = school
    }
    
    mutating  func next() -> String? {
        defer { idx += 1 }
        guard schoolList.count-1 >= idx
            else { return nil }
        
        return schoolList[idx]
    }
}

struct School: Sequence {
    fileprivate var list = Array(repeating: "school", count: 100000)
    var count: Int { return list.count }
    
    subscript(_ idx: Int ) -> String? {
        guard idx <= count-1
            else { return nil }
        return list[idx]
    }
    func makeIterator() -> SchoolIterator {
        return SchoolIterator(self)
    }
}
var schools = School()
for school in schools {
    print(school)
}


标签: swiftfor-loopcompilationiteratordynamic-dispatch

解决方案


您的 for 循环转换为:

var schools = School()
var iterator = schools.makeIterator()
while let school = iterator.next() {
    print(school)
}

注意这里没有什么是协议。schoolsis of type School, iteratoris of type SchoolIterator, 所做的一切next(如访问schoolList.count,或 的下标schoolList)也处理结构。关键是编译器可以准确地确定您的意思是哪个成员,因为它的(编译时)类型是一个结构。无需查找见证表。

比较一下,例如

func f<S: Sequence>(_ s: S) {
    for thing in s {
        ...
    }
/*
    var iterator: S.Iterator = s.makeIterator()
    while let thing = iterator.next() {
        ...
    }
*/
}

f(School())
f(1..<100)

编译器将如何调度调用iterator.next()?我特意添加了类型注释以清楚地说明发生了什么——这一次,编译器不知道next你的意思。是IndexingIterator.next()吗?或者SchoolIterator.next()?或者SomeOtherIterator.next()?请记住,我可以f使用任何类型的Sequence! S.Iterator 这就是为什么它需要在运行时查找实际类型的见证表- 无法确定next调用哪个。

至于为什么for i in 0..<100使用动态调度,嗯,乍一看,似乎有所有的结构:

let range: Range<Int> = 0..<100
var iterator: IndexingIterator<Range<Int>> = range.makeIterator()
while let i = iterator.next() {
    ...
}

但是,iterator.next实际上是这样的:

公共变异函数 next() -> Elements.Element?{ if _position == _elements.endIndex { return nil } let element = _elements[_position] _elements.formIndex(after: &_position) return element }

_elements定义如下:

public struct IndexingIterator<Elements: Collection> {
  
  internal let _elements: Elements

_elements可以是任何类型的Collection,所以同样,我们在编译时不知道哪个成员_elements[_position]_elements.formIndex指的是哪个成员。是Array.formIndex吗?或者Set.formIndex?我们只在运行时知道,当我们知道是什么时Elements

推荐阅读:https ://medium.com/@venki0119/method-dispatch-in-swift-effects-of-it-on-performance-b5f120e497d3


推荐阅读