您好,歡迎來電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊(cè)]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>通訊/手機(jī)編程>

怎樣提高iOS工程打包的速度

大?。?/span>0.3 MB 人氣: 2017-09-25 需要積分:1

過慢的編譯速度有非常明顯的副作用。一方面,程序員在等待打包的過程中可能會(huì)分心,比如刷刷朋友圈,看條新聞等等。這種認(rèn)知上下文的切換會(huì)帶來很多隱形的時(shí)間浪費(fèi)。另一方面,大部分 app 都有自己的持續(xù)集成工具,如果打包速度太慢, 會(huì)影響整個(gè)團(tuán)隊(duì)的開發(fā)進(jìn)度。

因此,本文會(huì)分別討論日常開發(fā)和持續(xù)集成這兩種場(chǎng)景,分析打包速度慢的瓶頸所在,以及對(duì)應(yīng)的解決方案。利用這些方案,筆者成功的把公司 app 的持續(xù)集成時(shí)間從 45 min 成功的減少到 9 min,效率提升高達(dá) 80%,理論上打包速度可以提升 10 倍以上。如果用一句話總結(jié)就是:

在絕對(duì)的實(shí)力(硬件)面前,一切技巧(軟件)都是浮云

日常開發(fā)

其實(shí)日常開發(fā)的優(yōu)化空間并不大,因?yàn)槟J(rèn)情況下 Xcode 會(huì)使用上次編譯時(shí)留下的緩存,也就是所謂的增量編譯。因此,日常開發(fā)的主要耗時(shí)由三部分構(gòu)成:

總耗時(shí) = 增量編譯 + 鏈接 + 生成調(diào)試信息(dSYM)

這里的增量編譯耗時(shí)比較短,即使是在我 14 年高配的 MacBook Pro(4核心,8 線程,2.5GHz i7 4870HQ,下文簡(jiǎn)稱 MBP) 上,也僅僅耗時(shí)十秒上下。我們的應(yīng)用代碼量大約一百多萬行,業(yè)內(nèi)超過這個(gè)量級(jí)的應(yīng)用應(yīng)該不多。鏈接和生成調(diào)試信息各花費(fèi)不到 20s,因此一次增量的編譯的時(shí)間開銷在半分鐘到一分鐘左右,我們逐個(gè)分析:

增量編譯: 因?yàn)楹臅r(shí)較短(大概十幾秒或者更少),幾乎不存在優(yōu)化的空間,但是非常容易惡化。因?yàn)橹挥蓄^文件不變的編譯單元才能被緩存,如果某個(gè)文件被 N 個(gè)文件引用,且這個(gè)文件的頭文件發(fā)生了變化,那么這 N 個(gè)文件都會(huì)重編譯。APP 的分層架構(gòu)一般都會(huì)做,但一個(gè)典型的誤區(qū)是在基礎(chǔ)庫的頭文件中使用宏定義,比如定義一些全局都可以讀取的常量,比如是否開啟調(diào)試,服務(wù)器的地址等等。這些常量一旦改變(比如為了調(diào)試或者切換到某些分支)就會(huì)導(dǎo)致應(yīng)用重編譯。

鏈接:鏈接沒有緩存,而且只能用單核進(jìn)行,因此它的耗時(shí)主要取決于單核性能和磁盤讀寫速度??紤]到我們的目標(biāo)文件一般都比較小,因此 4K 隨機(jī)讀寫的性能應(yīng)該會(huì)更重要一些。

調(diào)試信息:日常開發(fā)時(shí),并不需要生成 dSYM 文件,這個(gè)文件主要用于崩潰時(shí)查找調(diào)用棧,方便線上應(yīng)用進(jìn)行調(diào)試,而開發(fā)過程中的崩潰可以直接在 Xcode 中看到,關(guān)閉這個(gè)功能 不會(huì)對(duì)開發(fā)產(chǎn)生任何負(fù)面影響。

日常開發(fā)的優(yōu)化空間不大,即使是龐大的項(xiàng)目,落后的機(jī)器性能,關(guān)閉 dSYM 以后也就耗時(shí) 30s 左右。相比之下,打包速度可以優(yōu)化和討論的地方就比較多了。

持續(xù)集成

在利用 Jenkins 等工具進(jìn)行持續(xù)集成時(shí),緩存不推薦被使用。這是因?yàn)樘O果的緩存不夠穩(wěn)定,在某些情況下還存在 bug。比如明明本地已經(jīng)修復(fù)了 bug,可以編譯通過,但上次的編譯緩存沒有被正確清理,導(dǎo)致在打包機(jī)器上依然無法編譯通過。或者本地明明寫出了 bug,但同樣由于緩存問題,打包機(jī)器依然可以編譯通過。

因此,無論是手動(dòng)刪除 Derived Data 文件夾,還是調(diào)用 xcodebuild clean 命令,都會(huì)把緩存清空?;蛘咧苯邮褂?xcodebuild archive,會(huì)自動(dòng)忽略緩存。每次都要全部重編譯是導(dǎo)致打包速度慢的根本原因。以我們的項(xiàng)目為例,總計(jì) 45min 的打包時(shí)間中,有 40min 都在執(zhí)行 xcodebuild 這一行命令。

使用 CCache 緩存

最自然的想法就是使用緩存了,既然蘋果的緩存不靠譜,那么就找一個(gè)靠譜的緩存,比如 CCache。它是基于編譯器層面的緩存,根據(jù)目前反饋的情況看,并不存在緩存不一致的問題。根據(jù)筆者的實(shí)驗(yàn),使用 CCache 確實(shí)能夠較大幅度的提升打包速度,刪除緩存并使用 CCache 重編譯后,耗時(shí)只有十幾分鐘。

然而,CCache 最致命的問題是不支持 PCH 文件和 Clang modules。PCH 的本意是優(yōu)化編譯時(shí)間,我們假設(shè)有一個(gè)頭文件 A 依賴了 M 個(gè)頭文件,其中每個(gè)被依賴的頭文件又依賴了 N 個(gè) 頭文件,如下圖所示:

怎樣提高iOS工程打包的速度

由于 #import 的本質(zhì)就是把被依賴頭文件的內(nèi)容拷貝到自己的頭文件中來,因此頭文件 A 中實(shí)際上包含了 M * N 個(gè)頭文件的內(nèi)容,也就需要 M * N 次文件 IO 和相關(guān)處理。當(dāng)項(xiàng)目中每增加一個(gè)依賴頭文件 A 的文件,就會(huì)重復(fù)一次上述的 M * N 復(fù)雜度的過程。

PCH 文件的好處是,這個(gè)文件中的頭文件只會(huì)被編譯一次并緩存下來,然后添加到項(xiàng)目中 所有 的頭文件中去。上述問題倒是解決了,但很智障的一點(diǎn)是,所有文件都會(huì)隱式的依賴所有 PCH 中的文件,而真正需要被全局依賴的文件其實(shí)非常少。因此實(shí)際開發(fā)中,更多的人會(huì)把 PCH 當(dāng)成一種快速 import 的手段,而非編譯性能的優(yōu)化。前文解釋過,PCH 文件一旦發(fā)生修改,會(huì)導(dǎo)致徹徹底底,完完整整的項(xiàng)目重編譯,從而降低編譯速度。正是因?yàn)?PCH 的副作用甚至抵消了它帶來的優(yōu)化,蘋果已經(jīng)默認(rèn)不使用 PCH 文件了。

用來取代 PCH 的就是 Clang modules 技術(shù),對(duì)于開啟了這一選項(xiàng)的項(xiàng)目,我們可以用@import 來替代過去的 #import,比如:

@import UIKit;

等價(jià)于

#import 《UIKit/UIKit.h》

拋開自動(dòng)鏈接 framework 這些小特性不談,Clang modules 可以理解為模塊化的 PCH,它具備了 PCH 可以緩存頭文件的優(yōu)點(diǎn),同時(shí)提供了更細(xì)粒度的引用。

說回到 CCache,由于它不支持 PCH 和 Clang modules,導(dǎo)致無法在我們的項(xiàng)目中應(yīng)用。即使可以用,也會(huì)拖累項(xiàng)目的技術(shù)升級(jí),以這種代價(jià)來換取緩存,只怕是得不償失。

distcc

distcc 是一種分布式編譯工具,可以把需要被編譯的文件發(fā)送到其他機(jī)器上編譯,然后接收編譯產(chǎn)物。然而,經(jīng)過貼吧、貝聊、手Q 等應(yīng)用的多方實(shí)驗(yàn),發(fā)現(xiàn)并不適合 iOS 應(yīng)用。它的原理是多個(gè)客戶端共同編譯,但是絕大多數(shù)文件其實(shí)編譯時(shí)間非常短,并不值得通過網(wǎng)絡(luò)來回傳送,這種方案應(yīng)該只適合單個(gè)文件體量非常大的項(xiàng)目。在我們的項(xiàng)目中,使用 distcc大幅度增加了打包時(shí)間,大約耗時(shí) 1 小時(shí)左右。

定位瓶頸

在尋求外部工具無果后,筆者開始嘗試著對(duì)編譯時(shí)間直接做優(yōu)化。為了搞清楚這 40min 究竟是如何花費(fèi)的,我首先對(duì) xcodebuild 的輸出結(jié)果進(jìn)行詳細(xì)分析。

使用過 xcodebuild 命令的人都會(huì)知道,它的輸出結(jié)果對(duì)開發(fā)者并不友好,幾乎沒有可讀性,好在還有 xcpretty 這個(gè)工具可以格式化它:

gem install xcpretty

通過 gem 安裝后,只要把 xcodebuild 的輸出結(jié)果通過管道傳給 xcpretty 即可:

xcodebuild -scheme Release 。。. | xcpretty

非常好我支持^.^

(0) 0%

不好我反對(duì)

(0) 0%

      發(fā)表評(píng)論

      用戶評(píng)論
      評(píng)價(jià):好評(píng)中評(píng)差評(píng)

      發(fā)表評(píng)論,獲取積分! 請(qǐng)遵守相關(guān)規(guī)定!

      ?