【问题标题】:Swift function execution time measurement issueSwift函数执行时间测量问题
【发布时间】:2018-11-29 16:13:19
【问题描述】:

我有两个功能:

extension Array where Element: Hashable {
    func uniqueOrderly() -> [Element] {
        let startTime = CFAbsoluteTimeGetCurrent()
        var set = Set<Element>()
        var array = [Element]()
        for element in self {
            if set.contains(element) {
                continue
            }
            set.insert(element)
            array.append(element)
        }
        let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
        print("Time for uniqueOrderly: \(timeElapsed)")
        return array
    }
}

第二个:

public extension Sequence where Element: Equatable {
    func unique() -> [Element] {
        let startTime = CFAbsoluteTimeGetCurrent()
        var unique: [Element] {
            return reduce(into: []) {
                unique, x in
                if !unique.contains(x) {
                    unique.append(x)
                }
            }
        }
        let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
        print("Time for unique: \(timeElapsed)")
        return unique
    }
}

我正在对数组进行函数执行时间测量。

那是:

let arrayToFilter = [1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1,1,2,4,6,1,2,5,7,9,3,3,1]

实际的函数调用和结果是这样的:

arrayToFilter.unique() //Time for unique: 0.00012195110321044922
arrayToFilter.uniqueOrderly() Time for uniqueOrderly: 0.02329099178314209

但是当我更改函数调用的顺序时,我的 unique() 函数会显示可怕的时间测量结果。

arrayToFilter.uniqueOrderly() //Time for uniqueOrderly: 0.0013059377670288086
arrayToFilter.unique() //Time for unique: 8.940696716308594e-06

所以我的问题是为什么我在不同的函数调用顺序下会出现这种情况?此外,当我在 for 循环中运行这些测试时,测量结果完全不同。 (大约 +- 1 秒)

所有 mesurants 都是在 Playground 和具有 Release 构建设置的真实 iOS 应用程序中完成的(在模拟器上)。

测试规范:

Xcode 10.1 版

斯威夫特 4.2

【问题讨论】:

  • 首先,你在哪里测试这个?确保您在真实设备上的优化构建中进行测试。切勿在操场上测试性能。
  • @rmaddy 我用您要求的信息更新我的问题。
  • @rmaddy 如果您需要,我可以添加日志并删除执行时间。

标签: ios arrays swift sorting set


【解决方案1】:

您的unique() 实现会在计算unique 之前计算经过的时间。 unique 是一个计算的 var,并在访问时进行评估。

对于像这样相当短的列表,您的uniqueOrderly() 实现仍然比unique() 慢,因为与几乎总是在前几个元素中命中的线性搜索相比,插入集合的成本很高。

至于排序问题,这几乎可以肯定是您测试它的方式的产物。微分析非常具有挑战性。我通过将每个放入自己的.swift 文件并以swift -O &lt;file&gt; 运行来测试这些。但是,如果我按照您的方式将它们放在同一个文件中,并修复 unique() 以实际计时其活动,那么当以 swift -O &lt;file&gt; 运行时,时间会非常一致:

Time for uniqueOrderly: 1.800060272216797e-05
[1, 2, 4, 6, 5, 7, 9, 3]
Time for unique: 2.0265579223632812e-06
[1, 2, 4, 6, 5, 7, 9, 3]

Time for unique: 2.002716064453125e-05
[1, 2, 4, 6, 5, 7, 9, 3]
Time for uniqueOrderly: 2.9802322387695312e-06
[1, 2, 4, 6, 5, 7, 9, 3]

经过更多测试,我怀疑这些差异部分是内存分配(内存是从操作系统中以块的形式获取的,因此第一个分配器付出的代价比第二个更大)和 L1 缓存。如果您对两个不同的数组(指向内存缓存)进行排序,几乎所有差异都会消失。但是这个算法对数组的构成也很敏感,因为它有很多重复。

无论如何,这种微优化是没有意义的。你会整天追逐鬼魂。很难对微小数据块上的微小代码进行性能测试,并以适用于实际使用的方式对其进行优化。至少,您需要大得多的数组并测试许多不同类型的分布(大量重复而不是非常少)。您必须在 Playgrounds 之外进行测试,并且必须使用优化器。

【讨论】:

    猜你喜欢
    • 2016-01-28
    • 2011-09-09
    • 1970-01-01
    • 2023-03-09
    相关资源
    最近更新 更多