美文网首页
[Swift] 性能的一些测试

[Swift] 性能的一些测试

作者: 无衔 | 来源:发表于2018-08-04 19:43 被阅读252次

    1.Swift中数组性能的对比

    编写性能要求高的算法时,发现Swift对使用Array还是ContiguousArray;使用Class或者Struct作为元素,都会对性能带来明显的影响。

    对于"向数组增加元素"的操作,对性能提升起占主导作用的是要使用Struct。

    图1

    而对于"获取数组中的元素",使用ContiguousArray是最敏感的因素。

    图2

    如果算法跟数组操作十分相关,遇到性能不理想时,在条件允许的情况下首先应该用ContiguousArray替换Array。其次再考虑数据结构是Class改为用Struct。

    附上性能测试代码

    static let LogName = "swift"
    
    public class MyPoint {
        public var X :Float = 0
        public var Y :Float = 0
    }
    
    public struct MyPointStruct {
        public var X :Float = 0
        public var Y :Float = 0
    }
    
    public static func testAll(){
        
        
        let startTime1 = CFAbsoluteTimeGetCurrent()
        //float_multi_test()
        let endTime1 = CFAbsoluteTimeGetCurrent()
        let diff1:Double = (endTime1 - startTime1) * 1000
        print(LogName + " 浮点乘法 " + String(diff1))
    
        //-------------------------------
        
        let startTime2 = CFAbsoluteTimeGetCurrent()
        element_add()
        let endTime2 = CFAbsoluteTimeGetCurrent()
        let diff2:Double = (endTime2 - startTime2) * 1000
        print(LogName + " 数组增加元素 " + String(diff2))
        
        let startTime2_a = CFAbsoluteTimeGetCurrent()
        element_add_contiguousArray()
        let endTime2_a = CFAbsoluteTimeGetCurrent()
        let diff2_a:Double = (endTime2_a - startTime2_a) * 1000
        print(LogName + " 数组增加元素contiguous " + String(diff2_a))
    
        let startTime2_b = CFAbsoluteTimeGetCurrent()
        element_add_struct()
        let endTime2_b = CFAbsoluteTimeGetCurrent()
        let diff2_b:Double = (endTime2_b - startTime2_b) * 1000
        print(LogName + " 数组增加元素struct " + String(diff2_b))
        
        let startTime2_c = CFAbsoluteTimeGetCurrent()
        element_add_contiguousArray_struct()
        let endTime2_c = CFAbsoluteTimeGetCurrent()
        let diff2_c:Double = (endTime2_c - startTime2_c) * 1000
        print(LogName + " 数组增加元素contiguous_struct " + String(diff2_c))
        //-------------------------------
        
        
        let startTime3 = CFAbsoluteTimeGetCurrent()
        element_get()
        let endTime3 = CFAbsoluteTimeGetCurrent()
        let diff3:Double = (endTime3 - startTime3) * 1000
        print(LogName + " 数组获取元素 " + String(diff3))
        
        let startTime3_a = CFAbsoluteTimeGetCurrent()
        element_get_contiguousArray()
        let endTime3_a = CFAbsoluteTimeGetCurrent()
        let diff3_a:Double = (endTime3_a - startTime3_a) * 1000
        print(LogName + " 数组获取元素contiguous " + String(diff3_a))
        
        let startTime3_b = CFAbsoluteTimeGetCurrent()
        element_get_struct()
        let endTime3_b = CFAbsoluteTimeGetCurrent()
        let diff3_b:Double = (endTime3_b - startTime3_b) * 1000
        print(LogName + " 数组获取元素struct " + String(diff3_b))
        
        let startTime3_c = CFAbsoluteTimeGetCurrent()
        element_get_contiguousArray_struct()
        let endTime3_c = CFAbsoluteTimeGetCurrent()
        let diff3_c:Double = (endTime3_c - startTime3_c) * 1000
        print(LogName + " 数组获取元素contiguous " + String(diff3_c))
    }
    
    //浮点乘法
    public static func float_multi_test(){
        
        let times = 5999999
        var result:Float = 1
    
        for _ in 0 ..< times {
            for i in 2 ..< 999 {
                result = Float(1/Float(i)+0.5) * result + 0.5
            }
        }
        print(result)
    }
    
    
    //集合增加元素
    public static func element_add(){
        let times = 5000
        var array = [MyPoint]()
        
        for _ in 0 ..< times {
            array = [MyPoint]()
            for i in 1 ..< 9999 {
                let p = MyPoint()
                p.X = (Float(i) - 1 )/Float(i)
                p.Y = p.X * 1/Float(i)
                array.append(p)
            }
        }
        print(array.count)
    }
    
    //集合增加元素struct
    public static func element_add_struct(){
        let times = 5000
        var array = [MyPointStruct]()
        
        for _ in 0 ..< times {
            array = [MyPointStruct]()
            for i in 1 ..< 9999 {
                var p = MyPointStruct()
                p.X = (Float(i) - 1 )/Float(i)
                p.Y = p.X * 1/Float(i)
                array.append(p)
            }
        }
        print(array.count)
    }
    
    //集合增加元素contiguous
    public static func element_add_contiguousArray(){
        
        let times = 5000
        var array = ContiguousArray<MyPoint>()
        
        for _ in 0 ..< times {
            array = ContiguousArray<MyPoint>()
            for i in 1 ..< 9999 {
                let p = MyPoint()
                p.X = (Float(i) - 1 )/Float(i)
                p.Y = p.X * 1/Float(i)
                array.append(p)
            }
        }
        print(array.count)
    }
    
    //集合增加元素contiguous_struct
    public static func element_add_contiguousArray_struct(){
        
        let times = 5000
        var array = ContiguousArray<MyPointStruct>()
        
        for _ in 0 ..< times {
            array = ContiguousArray<MyPointStruct>()
            for i in 1 ..< 9999 {
                var p = MyPointStruct()
                p.X = (Float(i) - 1 )/Float(i)
                p.Y = p.X * 1/Float(i)
                array.append(p)
            }
        }
        print(array.count)
    }
    
    //集合获取元素
    public static func element_get(){
        
        let times = 5000
        var array = [MyPoint]()
        for i in 1 ..< 9999 {
            let p = MyPoint()
            p.X = (Float(i) - 1 )/Float(i)
            p.Y = p.X * 1/Float(i)
            array.append(p)
        }
        
        var result:Float = 0
        for _ in 0 ..< times {
            for i in 2 ..< 9999 {
                let p = array[i-2]
                let m = array[i-1]
                result = result + p.X + p.Y + m.X + m.Y
            }
        }
        print(result)
    }
    
    //集合获取元素contiguous
    public static func element_get_contiguousArray(){
        
        let times = 5000
        var array = ContiguousArray<MyPoint>()
        for i in 1 ..< 9999 {
            let p = MyPoint()
            p.X = (Float(i) - 1 )/Float(i)
            p.Y = p.X * 1/Float(i)
            array.append(p)
        }
        
        var result:Float = 0
        for _ in 0 ..< times {
            for i in 2 ..< 9999 {
                let p = array[i-2]
                let m = array[i-1]
                result = result + p.X + p.Y + m.X + m.Y
            }
        }
        print(result)
    }
    
    //集合获取元素struct
    public static func element_get_struct(){
        
        let times = 5000
        var array = [MyPointStruct]()
        for i in 1 ..< 9999 {
            var p = MyPointStruct()
            p.X = (Float(i) - 1 )/Float(i)
            p.Y = p.X * 1/Float(i)
            array.append(p)
        }
        
        var result:Float = 0
        for _ in 0 ..< times {
            for i in 2 ..< 9999 {
                let p = array[i-2]
                let m = array[i-1]
                result = result + p.X + p.Y + m.X + m.Y
            }
        }
        print(result)
    }
    
    //集合获取元素contiguous_struct
    public static func element_get_contiguousArray_struct(){
        
        let times = 5000
        var array = ContiguousArray<MyPointStruct>()
        for i in 1 ..< 9999 {
            var p = MyPointStruct()
            p.X = (Float(i) - 1 )/Float(i)
            p.Y = p.X * 1/Float(i)
            array.append(p)
        }
        
        var result:Float = 0
        for _ in 0 ..< times {
            for i in 2 ..< 9999 {
                let p = array[i-2]
                let m = array[i-1]
                result = result + p.X + p.Y + m.X + m.Y
            }
        }
        print(result)
    }
    
    记录一次实战效果大概是这样的

    1)没有改善前,算法运行耗时【124s】

    2)改用ContiguousArray后,算法运行耗时【60s】

    3)在ContiguousArray的基础上再把关键数据类型改用Struct,运行耗时变成【50s】

    我想这样的结果应该和大部分算法的调优过程会很接近,毕竟通常情况下读取数组比写数组的操作频率要高,那么ContiguousArray的使用会显得更要紧一些。

    2.Swift和ObjectC在乘法和数组操作上的对比

    在安卓开发时,高性能要求的部分可能就不会再用java实现了。所以对于性能优先的情况下,ios开发平台选择哪种开发语言也需要做个决断。
    性能测试代码还是跟上面贴的那段一样,改用ObjectC实现。
    简单测试得出的结论是,Swift用来写算法问题不大。

    图3
    Swift的乘法性能比Object稍差,但是集合操作有优势。不过这也取决于ObjectC的集合操作用法。鉴于题目是高性能要求的算法是否要ObjectC改写Swift,这里已经基本得到大致结论,ObjectC应该不会提升相对于Swift几何倍数的性能。所以不是非常极限的情况下,用Swift写算法是可以的。

    3.Swift和Java在乘法和数组操作上的对比

    最后再把鄙人经常干的事情,就是各个平台移植算法需要考虑的一个测试也做了。自从Swift产生,看到的都是好评一片。私以为,那是以ObjectC为参照的罢了。测试逻辑还是一样,最前面贴出的代码Swift翻版Java实现。结论大概就是下图这样的。


    图4
    图5

    这里Swift的添加和获取元素的操作,用的是它最快的组合ContiguousArray+Struct了。
    在这样简单的测试用例下, Swift还是能看到Java的车尾灯。性能有差距,对于这样的新语言来说请继续等待它的发展。

    最近一次Swift发展的后果就是,鄙人在不改算法的情况下,升级了系统版本和XCode,把Swift3升级到Swift3.3,结果就是性能下降10%。不管是OS有升级还是是Xcode有升级,反正都是苹果的锅。我只能说庆幸不是Swift当主打语言的开发者,对于是的人,你们辛苦了。

    相关文章

      网友评论

          本文标题:[Swift] 性能的一些测试

          本文链接:https://www.haomeiwen.com/subject/rrgmvftx.html