手工改進(jìn)XCode對Swift的響應(yīng)速度

前言

? Swift是一門非常優(yōu)秀的語言猾警。由于沒有歷史包袱,Swift得以集眾家之長隆敢,甚至可以說激進(jìn)发皿。默認(rèn)非空,類型安全拂蝎,嚴(yán)格的編譯時檢查穴墅,為開發(fā)者避免了許多的坑。而強(qiáng)大的類型推斷温自,面向協(xié)議的設(shè)計玄货,以及函數(shù)式支持,使得寫代碼成為一種非常愉悅的體驗悼泌。

? 當(dāng)然松捉,作為一門只有4年歷史的語言,Swift仍然有許多亟需改進(jìn)的地方馆里。對于大一些的項目隘世,日常開發(fā)中經(jīng)常會遇到代碼高亮失效,代碼提示失效的問題也拜,好好的一個IDE活生生變成了文本編輯器以舒。而論項目編譯時間,Swift項目的編譯速度通常是OC的3倍慢哈。這讓用iMac(8G內(nèi)存,筆記本機(jī)械硬盤)的筆者養(yǎng)成了經(jīng)常盯著屏幕發(fā)呆的習(xí)慣永票。

? 實際上卵贱,在Swift普及率較高的歐美開發(fā)者當(dāng)中,也有人表示侣集,對于大一些的項目键俱,寧肯用OC。不是Swift語言不好世分,實在是XCode太坑(當(dāng)然主要是swiftc這個前端的鍋)编振。好在,Swift團(tuán)隊的一些成員正在重點改進(jìn)編譯相關(guān)問題臭埋,目前的測試數(shù)據(jù)似乎不錯踪央。預(yù)計到XCode10實裝的時候臀玄,能夠明顯改進(jìn)項目的編譯速度,IDE變白板的情況也會改善很多畅蹂。

正文

? 在那之前健无,官方提供了一個工具,可以方便定位會產(chǎn)生編譯瓶頸的代碼液斜。具體做法如下(XCode 8 以上):

  1. 在項目的target中累贤,打開build setttings
  2. 在里面找到Other Swift Flags這一項
  3. 添加兩個參數(shù):-Xfrontend-warn-long-function-bodies=100,這里100單位是毫秒
  4. 重新編譯項目

以上的設(shè)置少漆,會在編譯耗時過長的函數(shù)方法上產(chǎn)生一個警告:

Instance method 'updateCurrentTime()' took 6228ms to type-check (limit: 100ms)

? 沒錯臼膏,6秒鐘,而且只是類型檢查??示损。對于類型檢查來說渗磅,100ms已經(jīng)是很大的數(shù)字了,大部分情況下屎媳,1ms左右才是合理的夺溢。

簡單說一下Swift代碼編譯過程:

  1. Parsing: 執(zhí)行語法檢查,生成AST語法樹烛谊,返回IDE語法錯誤及警告

  2. Semantic analysis: 語義分析风响,執(zhí)行類型檢查及類型推斷,生成類型完整的AST丹禀,返回IDE語義錯誤及警告状勤。

  3. Clang importer、SIL generation等等双泪。持搜。。

? 編譯過程的前兩步焙矛,直接決定了語法高亮和代碼提示的響應(yīng)速度葫盼。這個過程里Swift與OC最大的不同,便是引入了類型推斷村斟。實際上個人以為類型推斷是Swift能夠擁有簡潔優(yōu)雅語法的核心要素之一贫导。想當(dāng)年C++沒有auto的時候,用Vector之類的容器真是讓人欲仙欲死蟆盹。

真是成也類型推斷孩灯,敗也類型推斷。

我們來看看有問題的代碼:

// _lastTime和currentTime都是Double類型的屬性
guard abs(Int(round(_lastTime)) - Int(round(currentTime))) > 0 else {
            return
        }

其中abs()round()是對應(yīng)C函數(shù)的泛型重載逾滥,Int()是參數(shù)重載峰档,->是運(yùn)算符重載。

看來復(fù)雜表達(dá)式中有了過多泛型和重載之后,類型推斷的性能會指數(shù)級的下降讥巡,隨之而來的便是類型檢查時間過長掀亩。

因此,作為應(yīng)對手段尚卫,我們只能把代碼拆開:

let iLast: Int = Int(round(_lastTime))
let iCurr: Int = Int(round(currentTime))
let diff: Int = abs(iLast - iCurr)
guard diff > 0 else { return }

于是警告消失了归榕,通過拆分表達(dá)式和顯示類型提示,這段代碼的類型檢查速度提高了至少60倍吱涉。也由于這是代碼編譯過程的一部分刹泄,每次重編譯代碼都節(jié)省了5秒鐘的人生。

這是一個悲傷的故事??怎爵。

上面的例子可能比較特殊特石,不過除了重載以外,尾隨閉包也是類型推斷的重災(zāi)區(qū)鳖链。比如下面的代碼:

// 250ms type-check
let averageScore = Int(round(scoreResult
     .map{Float($0.value)}
     .reduce(0, +)
     / Float(scoreResult.count)))

還是拆代碼姆蘸,以及閉包的顯式類型提示:

// 10ms 以內(nèi)
let ast: Float = scoreResult
    .map{r in return Float(r.value)}
    .reduce(0, +)
    / Float(scoreResult.count)
let averageScore: Int = Int(round(ast))

這么把警告一個個干掉之后,雖然不可能完全解決問題芙委,但是滿屏黑白的情況會減少很多逞敷,至少不用經(jīng)常習(xí)慣性的按?S來刷新了。(沒錯灌侣,除了代碼鍵入推捐,保存也能觸發(fā)語法檢查)

后記

在官方對于swift編譯性能改進(jìn)的分析中(鏈接),提到了一些改進(jìn)方向:

  • 增量編譯模型過于保守侧啼,許多不必要的重新編譯牛柒。
  • 名字解析過于激進(jìn),讀入(反序列化)了過多的定義痊乾。
  • 前端任務(wù)的二次方級(復(fù)雜度)的任務(wù)中皮壁,很多引用的定義的類型檢查不夠lazy。
  • 表達(dá)式的類型推斷對于約束的推導(dǎo)沒有效率哪审,某些情況下(時間復(fù)雜度)是超線性甚至指數(shù)級的蛾魄。
  • SIL優(yōu)化的分析過程有時會緩存失敗,導(dǎo)致超線性的性能退化湿滓。
  • SIL生成IR的過程畏腕,在某些情況下(比如大的值類型)會生成過多的IR碼,影響后端LLVM的處理時間茉稠。

? 由此,我們可以期待把夸,在Swift 5發(fā)布的時候而线,無論是IDE的性能,還是代碼編譯速度,都有一個明顯的改善膀篮。

PS:Swift 5還可以期待async/awaitOwnership這樣的并發(fā)及運(yùn)行時性能改進(jìn)嘹狞,以及官方的主要目標(biāo),ABI穩(wěn)定(跨版本二進(jìn)制兼容的一部分)誓竿。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末磅网,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子筷屡,更是在濱河造成了極大的恐慌涧偷,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毙死,死亡現(xiàn)場離奇詭異燎潮,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)扼倘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門确封,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人再菊,你說我怎么就攤上這事爪喘。” “怎么了纠拔?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵秉剑,是天一觀的道長。 經(jīng)常有香客問我绿语,道長秃症,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任吕粹,我火速辦了婚禮种柑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匹耕。我一直安慰自己聚请,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布稳其。 她就那樣靜靜地躺著驶赏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪既鞠。 梳的紋絲不亂的頭發(fā)上煤傍,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機(jī)與錄音嘱蛋,去河邊找鬼蚯姆。 笑死五续,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的龄恋。 我是一名探鬼主播疙驾,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼郭毕!你這毒婦竟也來了它碎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤显押,失蹤者是張志新(化名)和其女友劉穎扳肛,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體煮落,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡敞峭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蝉仇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旋讹。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖轿衔,靈堂內(nèi)的尸體忽然破棺而出沉迹,到底是詐尸還是另有隱情,我是刑警寧澤害驹,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布鞭呕,位于F島的核電站,受9級特大地震影響宛官,放射性物質(zhì)發(fā)生泄漏葫松。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一底洗、第九天 我趴在偏房一處隱蔽的房頂上張望腋么。 院中可真熱鬧,春花似錦亥揖、人聲如沸珊擂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摧扇。三九已至,卻和暖如春挚歧,著一層夾襖步出監(jiān)牢的瞬間扛稽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工滑负, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留庇绽,地道東北人锡搜。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像瞧掺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子凡傅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,509評論 2 348