Swift数组访问器比原生数组慢5倍 - 这是推荐的?

end*_*vid 1 arrays ios swift metal

我在大阵列(图像)上做循环,通过仪器我发现主要的瓶颈是Array.subscript.nativePinningMutableAddressor,所以我做了这个单元测试来比较,

// average: 0.461 seconds (iPhone6 iOS 10.2) ~5.8 times slower than native arrays
func testArrayPerformance() {
    self.measure {
        var array = [Float](repeating: 1, count: 2048 * 2048)
        for i in 0..<array.count {
            array[(i+1)%array.count] = Float(i)
        }
    }
}

// average: 0.079 seconds
func testNativeArrayPerformance() {
    self.measure {
        let count = 2048 * 2048
        let array = UnsafeMutablePointer<Float>.allocate(capacity: count)
        for i in 0..<count {
            array[(i+1)%count] = Float(i)
        }
        array.deallocate(capacity: count)
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,本机数组要快得多.还有其他方法可以更快地访问阵列吗?"不安全"听起来并不"安全",但在这种情况下你会做些什么呢?是否有其他类型的数组包装本机?

有关更复杂的示例,您可以看到本文中的注释:使用带符号距离字段在Metal中呈现文本 我在Swift中重新实现了该示例,并且原始实现需要52秒才能启动,https:// github .COM/endavid/VidEngine /树/ textprimitive失效

切换到本机阵列后,我下降到10秒,https://github.com/endavid/VidEngine/tree/fontatlas-array-optimization

在Xcode 8.3.3上测试过.

Edit1:此测试的时间是在Debug配置中,但是Signed Distance Fields示例的时间是Release配置.感谢评论中单元测试的微优化(计数,初始化),但在现实世界中,这些可以忽略不计,内存缓冲解决方案在iOS上仍然快5倍.

Edit2:以下是签名距离字段示例中最昂贵函数的时序(iPhone6上的Instruments会话),

使用Swift数组, 使用Swift数组

使用内存缓冲区, 使用内存缓冲区

Edit3:除了性能问题,我使用Swift数组时遇到了严重的内存问题.NSKeyedArchiver会耗尽内存并导致应用崩溃.我不得不使用字节缓冲区,并将其存储在一个NSData.参考.commit:https://github.com/endavid/VidEngine/commit/6c1822523a2b18759f294def3188755eaaf98b41

所以我想我的问题的答案是:对于大数字数据数组(例如图像),最好使用内存缓冲区.

Ale*_*ica 5

简单地count将速度从0.2s 缓存到0.14s,这是基于指针的代码所用时间的两倍.考虑到基于数组的代码对所有元素进行预初始化,这是完全可以预料到的1.

基线:

在此输入图像描述

缓存之后count:

在此输入图像描述