数组 – 为什么连续遍历一个Structs数组比一个Classes数组更快?

数组 – 为什么连续遍历一个Structs数组比一个Classes数组更快?,第1张

概述我正在开发一个使用 Swift的游戏,我有一个静态的位置数据数组,我用它来在游戏循环中进行处理.我最初使用一个Structs数组来保存这些数据,但我决定切换到类,所以我可以使用引用.但是在进行更改和分析之后,我注意到CPU在处理此数据的方法上花费的时间比在使用Structs时花费的时间多得多. 所以我决定创建一个简单的测试来看看发生了什么. final class SomeClass {}str 我正在开发一个使用 Swift的游戏,我有一个静态的位置数据数组,我用它来在游戏循环中进行处理.我最初使用一个Structs数组来保存这些数据,但我决定切换到类,所以我可以使用引用.但是在进行更改和分析之后,我注意到cpu在处理此数据的方法上花费的时间比在使用Structs时花费的时间多得多.

所以我决定创建一个简单的测试来看看发生了什么.

final class SomeClass {}struct SomeStruct {}let classes = [    SomeClass(),SomeClass(),]let structs = [    SomeStruct(),SomeStruct(),]
func test1() {    for i in 0...10000000 {        for s in classes {}    }}func test2() {    for i in 0...10000000 {        for s in structs {}    }}

Test1需要15.4722579717636 s而Test2仅需0.276068031787872 s.通过结构阵列连续迭代的速度提高了56倍.所以我的问题是,这是为什么?我正在寻找一个详细的答案.如果我不得不猜测,我会说结构本身按顺序存储在内存中,而类只存储为地址.所以他们每次都需要被解除引用.但话说回来,每次都不需要复制结构吗?

旁注:两个数组都很小,但我不断迭代它们.如果我将代码更改为迭代一次但是使数组非常大,如下所示:

for i in 0...10000000 {   structs.append(SomeStruct())   classes.append(SomeClass())}func test1() {    for s in classes {}}func test2() {    for s in structs {}}

然后我得到以下结果:Test1需要0.841085016727448 s而Test2需要0.00960797071456909 s.结构需要快88倍.

我正在使用OS X发布版本,优化级别设置为最快,最小[-Os]

编辑

根据要求,我编辑了这个问题,以包含一个测试,其中结构和类不再是空的.它们使用我在游戏中使用的相同属性.仍然没有什么区别.结构仍然快得多,我不知道为什么.希望有人能提供答案.

import Foundationfinal class StructTest {    let surfaceFrames = [        SurfaceFrame(a: SurfacePoint(x: 0,y: 410),b: SurfacePoint(x: 0,y: 400),c: SurfacePoint(x: 875,surfaceID: 0,dynamic:false),SurfaceFrame(a: SurfacePoint(x: 880,y: 304),b: SurfacePoint(x: 880,y: 294),c: SurfacePoint(x: 962,surfaceID: 1,SurfaceFrame(a: SurfacePoint(x: 787,y: 138),b: SurfacePoint(x: 791,y: 129),c: SurfacePoint(x: 1031,y: 248),surfaceID: 2,SurfaceFrame(a: SurfacePoint(x: 523,b: SurfacePoint(x: 523,y: 128),c: SurfacePoint(x: 806,y: 144),surfaceID: 3,SurfaceFrame(a: SurfacePoint(x: 1020,y: 243),b: SurfacePoint(x: 1020,y: 233),c: SurfacePoint(x: 1607,y: 241),surfaceID: 4,SurfaceFrame(a: SurfacePoint(x: 1649,b: SurfacePoint(x: 1649,c: SurfacePoint(x: 1731,y: 305),surfaceID: 5,SurfaceFrame(a: SurfacePoint(x: 1599,y: 240),b: SurfacePoint(x: 1595,y: 231),c: SurfacePoint(x: 1852,surfaceID: 6,SurfaceFrame(a: SurfacePoint(x: 1807,y: 141),b: SurfacePoint(x: 1807,y: 131),c: SurfacePoint(x: 2082,surfaceID: 7,SurfaceFrame(a: SurfacePoint(x: 976,y: 413),b: SurfacePoint(x: 976,y: 403),c: SurfacePoint(x: 1643,y: 411),surfaceID: 8,SurfaceFrame(a: SurfacePoint(x: 1732,b: SurfacePoint(x: 1732,c: SurfacePoint(x: 2557,surfaceID: 9,SurfaceFrame(a: SurfacePoint(x: 2130,y: 490),b: SurfacePoint(x: 2138,y: 498),c: SurfacePoint(x: 2109,y: 512),surfaceID: 10,SurfaceFrame(a: SurfacePoint(x: 1598,y: 828),b: SurfacePoint(x: 1597,y: 818),c: SurfacePoint(x: 1826,y: 823),surfaceID: 11,SurfaceFrame(a: SurfacePoint(x: 715,y: 826),b: SurfacePoint(x: 715,y: 816),c: SurfacePoint(x: 953,surfaceID: 12,SurfaceFrame(a: SurfacePoint(x: 840,y: 943),b: SurfacePoint(x: 840,y: 933),c: SurfacePoint(x: 920,surfaceID: 13,SurfaceFrame(a: SurfacePoint(x: 1005,y: 1011),b: SurfacePoint(x: 1005,y: 1001),c: SurfacePoint(x: 1558,surfaceID: 14,SurfaceFrame(a: SurfacePoint(x: 1639,b: SurfacePoint(x: 1639,c: SurfacePoint(x: 1722,y: 942),surfaceID: 15,SurfaceFrame(a: SurfacePoint(x: 1589,y: 825),b: SurfacePoint(x: 1589,y: 815),c: SurfacePoint(x: 1829,surfaceID: 16,SurfaceFrame(a: SurfacePoint(x: 0,y: 0),b: SurfacePoint(x: 1,y: 1),c: SurfacePoint(x: 2,y: 2),surfaceID: 17,dynamic:true)    ]    func run() {        let startTime = CFabsoluteTimeGetCurrent()        for  i in 0 ... 10000000 {            for s in surfaceFrames {            }        }        let timeElapsed = CFabsoluteTimeGetCurrent() - startTime        println("Time elapsed \(timeElapsed) s")    }}struct SurfacePoint {    var x,y: Int}struct SurfaceFrame {    let a,b,c :SurfacePoint    let surfaceID: Int    let dynamic: Bool}
import Foundationfinal class Classtest {    let surfaceFrames = [        SurfaceFrame(a: SurfacePoint(x: 0,y: Int}final class SurfaceFrame {    let a,c :SurfacePoint    let surfaceID: Int    let dynamic: Bool    init(a: SurfacePoint,b: SurfacePoint,c: SurfacePoint,surfaceID: Int,dynamic: Bool) {        self.a = a        self.b = b        self.c = c        self.surfaceID = surfaceID        self.dynamic = dynamic    }}

在此测试中,类使用了14.5261079668999 s,而使用结构的测试仅花费了0.310304999351501 s.结构快了47倍.

解决方法 正如Martin R推荐的那样,我描述了两个测试,实际上,保留/释放调用使得遍历类数组比迭代结构数组要慢得多.为了清楚起见,这是我跑的测试.

import Foundationfinal class SomeClass {}struct SomeStruct {}var classes = [    SomeClass(),]var structs = [    SomeStruct(),]let startTime = CFabsoluteTimeGetCurrent()/*structtest()classtest()*/let timeElapsed = CFabsoluteTimeGetCurrent() - startTimeprintln("Time elapsed \(timeElapsed) s")
func structtest() {    for i in 0 ... 1000000 {        for e in structs {}    }}
func classtest() {    for i in 0 ... 1000000 {        for e in classes {}    }}

以下是使用仪器进行两种测试分析的图片.您可以通过将每次迭代期间Classes测试几乎所有时间花在保留/释放上的运行时间加起来来看.我有兴趣看看Swift 2.0如何处理这个问题.

结构

所以出于好奇,我想如果我可以通过直接在数组上执行指针算法来绕过retain / release调用会发生什么(旁注:我建议你永远不要在真正的应用程序中这样做).所以我创建了最后一个测试.但是在这个测试中,我不是多次迭代数组,而是创建一个大型数组并迭代一次,因为这是大多数开销发生的地方.我还决定在此测试中访问属性以减少优化中的模糊性.

所以这是最终测试的结果:

>对大型Struct阵列进行一次迭代:1.00037097930908 s
>对大型类阵列的一次迭代:11.3165299892426 s
>使用指针对大型Struct数组进行一次迭代
算术:0.773443996906281 s
>使用指针对大型Class数组进行一次迭代
算术:2.81995397806168 s

以下是测试代码.

final class SomeClass {    var a: Int    init(a: Int) {        self.a = a    }}struct SomeStruct {    var a: Int    init(a: Int) {        self.a = a    }}var classes: [SomeClass] = []var structs: [SomeStruct] = []var total: Int = 0for i in 0 ... 100000000 {    classes.append(SomeClass(a:i))    structs.append(SomeStruct(a:i))}let startTime = CFabsoluteTimeGetCurrent()/*structtest()classtest()structTestPointer()classtestPointer()*/let timeElapsed = CFabsoluteTimeGetCurrent() - startTimeprintln("Time elapsed \(timeElapsed) s")func structtest() {    for someStruct in structs {        let a = someStruct.a        total = total &+ a    }}func structTestPointer() {    var pointer = UnsafePointer<SomeStruct>(structs)    for j in 0 ..< structs.count {        let someStruct = pointer.memory        let a = someStruct.a        total = total &+ a        pointer++    }}func classtest() {    for someClass in classes {        let a = someClass.a        total = total &+ a    }}func classtestPointer() {    var pointer = UnsafePointer<SomeClass>(classes)    for j in 0 ..< classes.count {        let someClass = pointer.memory        let a = someClass.a        total = total &+ a        pointer++    }}
总结

以上是内存溢出为你收集整理的数组 – 为什么连续遍历一个Structs数组比一个Classes数组更快?全部内容,希望文章能够帮你解决数组 – 为什么连续遍历一个Structs数组比一个Classes数组更快?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1016470.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存