美文网首页iOSSwiftavailable
如何有效提高swift的编译速度

如何有效提高swift的编译速度

作者: MrZhaoCn | 来源:发表于2017-05-01 23:27 被阅读1047次

    swift 作为一门新语言,受到了广大开发者的喜爱,苹果也极力在推swift,甚至最终会替换掉OC,笔者现在公司的项目也采用了swift编写(三方库除外),但发现一个很严重的问题就是编译速度实在是难以让人接受,因此笔者在如何提高swift的编译速度方面做了相关调研,并将所学到的应用到项目中,项目的编译速度得到了很大的提升。文章将从两方面来介绍如何提高swift项目的编译速度,一是从代码优化上,一是从编译器设置上。

    前言#

    在改善项目的编译速度前,有必要知道到底是哪些函数编译耗时,哪些文件编译耗时,Robert 一个swift爱好者为我们提供了一个统计函数编译时间的工具https://github.com/RobertGummesson/BuildTimeAnalyzer-for-Xcode,利用该工具能很方便的查出编译耗时的地方。

    一代码层面优化#

    1.尽量避免类型推断,能确定类型的一定要给出具体类型

    func test1() {
            let number = 32
            let string = ""
            let label = UILabel()
            let dict = ["string1":"string","number":10,"label":label] as [String : Any]
            var strings: [String] = []
        }
        func test2() {
            let number:Int = 32
            let string:String = ""
            let label:UILabel = UILabel()
            let dict:[String:Any] = ["string1":"string","number":10,"label":label] as [String : Any]
            var strings: [String] = [String]()
        }
    
    屏幕快照 2017-05-01 22.36.45.png

    test1采用了类型推断耗时37.3ms,test2采用了精确的类型定义耗时10.5ms,减少了近三倍多的编译时间。

    2.nil类型问题
    由于swift存在可选值,因此某些对象的值可能为空,这在代码处理时可能会导致编译很慢

    func test3() ->Int {
            var number1:Int?
            var number2:Int?
            var number3:Int?
            return 10 + (number1 ?? 0) + (number2 ?? 0) + (number3 ?? 0)
        }
        func test4() ->Int {
            var total = 10
            var number1:Int?
            var number2:Int?
            var number3:Int?
            if let number1 = number1 {
                total = total + number1
            }
            
            if let number2 = number2 {
                total = total + number2
            }
            if let number3 = number3 {
                total = total + number3
            }
            return total
        }
    
    屏幕快照 2017-05-01 22.44.38.png

    test3中number1,2,3可能存在nil,因此在返回时如果为nil,则给了默认值0,结果编译时间为7841.3ms,将近8s,太不可思议。而test4中对于可能为nil的情况下进行了可选值绑定来判断是否为nil,编译时间为1.7ms,编译时间跟test3不在一个量级上面,因此对于可能为nil的情况下,建议采用可选值绑定的方式来判断,避免采用三的处理方式。

    3.+ +=运算
    直接看代码

    func test5() {
            var arrays = [Int]()
            let arr1 = [1,2,3]
            let arr2 = [3,4,5]
            arrays += arr1 + arr2 + [10]
        }
        func test6() {
            var arrays:[Int] = [Int]()
            let arr1 = [1,2,3]
            let arr2 = [3,4,5]
            arrays.append(contentsOf: arr1)
            arrays.append(contentsOf: arr2)
            arrays.append(contentsOf: [10])
        }
    
    屏幕快照 2017-05-01 22.54.22.png

    test5采用+ 将数组进行合并耗时140.9ms,而test5采用系统提供的api进行合并耗时2.3ms,因此对于数组合并的情况建议采用test6的形式。

    4.复杂表达式计算
    直接看代码

    func test7(string1:String,string2:String) {
            let string = string1 + "你好" + string2 + "\(10)"
        }
        func test8(string1:String,string2:String) {
            var string = string1
            string = string + "你好"
            string = string + string2
            string = string + "\(10)"
            
        }
    
    屏幕快照 2017-05-01 22.59.05.png

    test7表达式虽清晰,但复杂,编译耗时23.4ms,test8将test7的表达式拆成几部分,编译时间1.3ms,表达式越简单,编译时间越短,因此是编写简洁明了的表达式,还是编写对编译器友好的表达式,我们是需要权衡的。

    5.函数放在extension中,比不放在extension中编译更耗时,使用闭包也比较耗时。

    二 编译器层面优化编译时间#

    1. WHO
      简单地说,Whole-Module Optimization(全模块优化,以下简称 WMO),即在编译项目时,将同属于一个 Module(可以理解为一个 Target、一个 Package)的所有源代码都串起来,进行整体的一个分析与优化,区别于 Single-File Optimization(单文件优化,以下简称 SFO),WMO 可以更好的统筹全局,去 inline 函数调用、排除死函数(即写了却从不调用的函数)等等,使编译速度加快。但问题来了,WMO 只是在 Release 模式下成为了默认且推荐的选项,在 Debug 模式下默认依然是 None。

    2.利用Uber团队在利用swift3重写客户端中发现的黑科技
    Uber 的开发团队偶然发现如果把所有 Model 文件全部合并到一个文件去编译, 那编译时间会从 1min 35s 减少到 17s, 那么我们如果把所有代码文件都合并到一起, 那就可以极大地优化编译速度了。
    WHO(Whole-Module-Optimization) 也会把文件合并起来再进行编译, 实际使用时我们发现编译虽然快了, 但对于编译时间的减少还是远没有直接把文件合并到一起那么有效. 主要原因是因为 WHO 除了合并文件之外, 还会在预编译阶段做这些事情: 检测没有被调用的方法和类型, 在预编译期去掉它们,给没有被继承的类, 没有被继承的方法加上 final 标签, 给编译器提供更多信息, 以便这些方法被优化为静态调用或者是内联进去,这些优化会对于程序的效率有很大的提升, 但编译时间会有所增加。

    Uber 的团队发现通过增加一个编译宏就可以做到只合并文件, 而不做优化. 进入工程文件设置 -> Build Setting -> Add User-Defined Settings, key 为 SWIFT_WHOLE_MODULE_OPTIMIZATION
    , value 设为 YES
    , 然后把优化级别设为 None
    就可以了.

    Screen Shot 2017-04-27 at 5.55.10 PScreen Shot 2017-04-27 at 5.55.10 P

    相关文章

      网友评论

        本文标题:如何有效提高swift的编译速度

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