Swift   发布时间:2022-04-30  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了数组 – 为什么连续遍历一个Structs数组比一个Classes数组更快?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_489_2@
我正在开发一个使用 Swift的游戏,我有一个静态的位置数据数组,我用它来在游戏循环中进行处理.我最初使用一个Structs数组来保存这些数据,但我决定切换到类,@R_756_9447@使用引用.但是在进行更改和分析之后,我注意到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 Foundation

final 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 Foundation

final 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倍.

@H_489_2@

解决方法

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

import Foundation

final class someClass {}

struct SomeStruct {}

var classes = [
    someClass(),]
var structs = [
    SomeStruct(),]

let startTime = CFAbsoluteTimeGetCurrent()
/*
structtest()
classtest()
*/
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
println("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 @R_62_10586@l: Int = 0

for i in 0 ... 100000000 {
    classes.append(someClass(a:i))
    structs.append(SomeStruct(a:i))
}

let startTime = CFAbsoluteTimeGetCurrent()
/*structtest()
classtest()
structTestPointer()
classTestPointer()*/
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
println("Time elapsed \(timeElapsed) s")

func structtest() {
    for someStruct in structs {
        let a = someStruct.a
        @R_62_10586@l = @R_62_10586@l &+ a
    }
}

func structTestPointer() {
    var pointer = UnsafePointer<SomeStruct>(structs)
    for j in 0 ..< structs.count {
        let someStruct = pointer.memory
        let a = someStruct.a
        @R_62_10586@l = @R_62_10586@l &+ a
        pointer++
    }
}

func classtest() {
    for someClass in classes {
        let a = someClass.a
        @R_62_10586@l = @R_62_10586@l &+ a
    }
}

func classTestPointer() {
    var pointer = UnsafePointer<someClass>(classes)
    for j in 0 ..< classes.count {
        let someClass = pointer.memory
        let a = someClass.a
        @R_62_10586@l = @R_62_10586@l &+ a
        pointer++
    }
}
@H_489_2@ @H_489_2@
@H_489_2@
@H_489_2@

大佬总结

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

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

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。