如何提升iOS 工程打包速度

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

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

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

日常開(kāi)發(fā)

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

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

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

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

鏈接:鏈接沒(méi)有緩存棕洋,而且只能用單核進(jìn)行挡闰,因此它的耗時(shí)主要取決于單核性能和磁盤(pán)讀寫(xiě)速度£蹋考慮到我們的目標(biāo)文件一般都比較小摄悯,因此 4K 隨機(jī)讀寫(xiě)的性能應(yīng)該會(huì)更重要一些。

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

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

持續(xù)集成

在利用 Jenkins 等工具進(jìn)行持續(xù)集成時(shí)泻云,緩存不推薦被使用艇拍。這是因?yàn)樘O(píng)果的緩存不夠穩(wěn)定狐蜕,在某些情況下還存在 bug。比如明明本地已經(jīng)修復(fù)了 bug卸夕,可以編譯通過(guò)层释,但上次的編譯緩存沒(méi)有被正確清理,導(dǎo)致在打包機(jī)器上依然無(wú)法編譯通過(guò)娇哆∨壤郏或者本地明明寫(xiě)出了 bug,但同樣由于緩存問(wèn)題碍讨,打包機(jī)器依然可以編譯通過(guò)治力。

因此,無(wú)論是手動(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 緩存

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

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

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

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

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

@import UIKit;

等價(jià)于

#import

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

說(shuō)回到 CCache遇骑,由于它不支持 PCH 和 Clang modules,導(dǎo)致無(wú)法在我們的項(xiàng)目中應(yīng)用揖曾。即使可以用落萎,也會(huì)拖累項(xiàng)目的技術(shù)升級(jí),以這種代價(jià)來(lái)?yè)Q取緩存炭剪,只怕是得不償失练链。

distcc

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

定位瓶頸

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

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

gem install xcpretty

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

xcodebuild -scheme Release ... | xcpretty

下面是官方文檔中的 Demo:

我只對(duì)其中的編譯部分感興趣国裳,所以簡(jiǎn)單的做下過(guò)濾形入,我們就可以得到格式高度統(tǒng)一的輸出:

Compiling A.m

Compiling B.m

Compiling ...

Compiling N.m

到了這一步,終于可以做最關(guān)鍵的計(jì)算了缝左,我們可以通過(guò)設(shè)置定時(shí)器亿遂,計(jì)算相鄰兩行輸出之間的間隔,這個(gè)間隔就是文件的編譯時(shí)間渺杉。當(dāng)然蛇数,也有類(lèi)似的輔助工具做好了這個(gè)邏輯:

npm install gnomon

簡(jiǎn)單的做一下排序,就可以看到最耗時(shí)的前 200 個(gè)文件了是越,還可以針對(duì)文件后綴作區(qū)分耳舅,計(jì)算總耗時(shí)等等。經(jīng)過(guò)排查倚评,我們發(fā)現(xiàn)一半的編譯時(shí)間都花在了編譯 protobuf 文件上浦徊。

工程設(shè)置

除了針對(duì)超長(zhǎng)耗時(shí)的文件進(jìn)行 case-by-case 的分析外,另一種方案是調(diào)整工程設(shè)置天梧。一般來(lái)說(shuō)盔性,我們的持續(xù)集成工具主要是用來(lái)給產(chǎn)品經(jīng)理或者測(cè)試人員使用,用來(lái)體驗(yàn)功能或者驗(yàn)證 Bug呢岗,除非是需要上架 App Store冕香,否則并不需要關(guān)心運(yùn)行時(shí)性能蛹尝。然而在手機(jī)上使用的 Release 模式,默認(rèn)會(huì)開(kāi)啟各種優(yōu)化暂筝,這些優(yōu)化都是犧牲編譯性能箩言,換取運(yùn)行時(shí)速度硬贯,對(duì)于上架的包而言無(wú)可厚非焕襟,但對(duì)于那些 Daily Build 包來(lái)說(shuō),就顯得得不償失了饭豹。

因此鸵赖,加速打包的思路和優(yōu)化的思路是完全互逆的,我們要做的就是關(guān)閉一切可能的優(yōu)化拄衰。這里推薦一篇文章:關(guān)于Xcode編譯性能優(yōu)化的研究工作總結(jié)它褪,可以說(shuō)相當(dāng)全面了。

經(jīng)過(guò)對(duì)其中各個(gè)參數(shù)的查找資料和嘗試關(guān)閉翘悉,按照提升速度的降序排列茫打,簡(jiǎn)單整理幾個(gè):

僅支持 armv7 指令集。手機(jī)上的指令集都屬于 ARM 系列妖混,從老到新依次是 armv7老赤、armv7s 和 arm64。新的指令集可以兼容舊的機(jī)型制市,但舊的機(jī)型不能兼容新的指令集抬旺。默認(rèn)情況下我們打出來(lái)的包會(huì)有 armv7 和 arm64 兩種指令集, 前者負(fù)責(zé)兜底祥楣,而對(duì)于支持 arm64 指令集的機(jī)型來(lái)說(shuō)开财,使用最新的指令集可以獲得更好的性能。當(dāng)然代價(jià)就是生成兩種指令集花費(fèi)了更多時(shí)間误褪。所以在急速打包模式下责鳍,我們只生成 armv7 這種最老的指令集,犧牲了運(yùn)行時(shí)性能換取編譯速度兽间。

關(guān)閉編譯優(yōu)化历葛。優(yōu)化的基本原理是犧牲編譯時(shí)性能,追求運(yùn)行時(shí)性能渡八。常見(jiàn)的優(yōu)化有編譯時(shí)刪除無(wú)用代碼啃洋,保留調(diào)試信息,函數(shù)內(nèi)聯(lián)等等屎鳍。因此提升打包速度的秘訣就是反其道而行之宏娄,犧牲運(yùn)行時(shí)性能來(lái)?yè)Q取編譯時(shí)性能。筆者做的兩個(gè)最主要的優(yōu)化是把Optimize level改成 O0逮壁,表示不做任何優(yōu)化孵坚。

使用虛擬磁盤(pán)。編譯過(guò)程中需要大量的磁盤(pán) IO,這主要發(fā)生在Derived Data目錄下卖宠,因此如果內(nèi)存足夠巍杈,可以考慮劃出 4G 左右的內(nèi)存,建一個(gè)虛擬磁盤(pán)扛伍,這樣將會(huì)把磁盤(pán) IO 優(yōu)化為 內(nèi)存 IO筷畦,從而提高速度。由于打包機(jī)器每次都會(huì)重編譯刺洒,因此并不需要擔(dān)心重啟機(jī)器后緩存丟失的問(wèn)題鳖宾。

不生成 dYSM 文件,前文已經(jīng)介紹過(guò)逆航。

一些其他的選項(xiàng)鼎文,參考前面推薦的文章。

在以上幾個(gè)操作中因俐,精簡(jiǎn)指令集的作用最大拇惋,大約可以把編譯時(shí)間從 45 min 減少到 30min 以?xún)?nèi),配合關(guān)閉編譯優(yōu)化抹剩,可以進(jìn)一步把打包時(shí)間減少到 20min撑帖。虛擬磁盤(pán)大約可以減少兩三分鐘的編譯時(shí)間,dSYM 耗時(shí)大約二十秒吧兔,其它選項(xiàng)的優(yōu)化程度更低磷仰,大約在幾秒左右,沒(méi)有精確測(cè)算境蔼。

因此灶平,一般來(lái)說(shuō)只要精簡(jiǎn)指令集并關(guān)閉優(yōu)化即可,有條件的機(jī)器可以使用虛擬磁盤(pán)箍土,不建議再做其它修改逢享。

二進(jìn)制化

二進(jìn)制化主要指的是利靜態(tài)庫(kù)代替源碼,避免編譯吴藻。前文已經(jīng)介紹過(guò)如何分析文件的耗時(shí)瞒爬,因此二進(jìn)制化的收益非常容易計(jì)算出來(lái)。由于團(tuán)隊(duì)分工問(wèn)題沟堡,筆者沒(méi)有什么二進(jìn)制化的經(jīng)驗(yàn)侧但,一般來(lái)說(shuō)這個(gè)優(yōu)化比較適合基礎(chǔ)架構(gòu)組去實(shí)施。

硬件加速

以上主要是通過(guò)修改軟件的方式來(lái)加速打包航罗,自從公司申請(qǐng)了 2013 年款 Mac Pro(Xeon-E5 1630 6 核 12 線程禀横,16G 內(nèi)存,256G SSD 標(biāo)配粥血,下文簡(jiǎn)稱(chēng) Mac Pro)后柏锄,不需要修改任何配置酿箭,僅僅是簡(jiǎn)單的遷移打包機(jī)器,就可以把打包時(shí)間降低到 15 min趾娃,配和上一節(jié)中的前三條優(yōu)化缭嫡,最終的打包時(shí)間大概在 10min 以?xún)?nèi)。

在我的黑蘋(píng)果(i7 7820x 8 核 16 線程抬闷,16G 內(nèi)存妇蛀,三星? PM 961 512G SSD,下文簡(jiǎn)稱(chēng)黑蘋(píng)果)上饶氏,即使不開(kāi)啟任何優(yōu)化讥耗,從零開(kāi)始編譯也僅需 5min。如果將 protobuf 文件二進(jìn)制化疹启,再配合一些工程設(shè)置的優(yōu)化,我不敢想象需要花多長(zhǎng)時(shí)間蔼卡,預(yù)計(jì)在 4min 左右吧喊崖,速度提升了大概 11 倍。

編譯是一個(gè)考驗(yàn)多核性能的操作雇逞,在我的黑蘋(píng)果上荤懂,編譯時(shí)可以看到 8 個(gè) CPU 的負(fù)載都達(dá)到了 100%,因此在一定范圍內(nèi)(比如 10 核以?xún)?nèi))塘砸,提升 CPU 核數(shù)遠(yuǎn)比提升單核主頻對(duì)編譯速度的影響大节仿。至于某些 20 核以上、單核性能較低的 CPU 編譯性能如何掉蔬,希望有經(jīng)驗(yàn)的讀者給予反饋廊宪。

優(yōu)化點(diǎn)總結(jié)

下表總結(jié)了文章中提到的各種優(yōu)化手段帶來(lái)的速度提升,參考原始時(shí)間均為 45 min(打包機(jī)器:13 寸? MacBook Pro):

方案序號(hào)優(yōu)化方案優(yōu)化后耗時(shí) (min)時(shí)間減少百分比

1不常修改的文件二進(jìn)制化2544.4%

2精簡(jiǎn)指令集2740%

3關(guān)閉編譯優(yōu)化3815.6%

4使用 Mac Pro1566.7%

5虛擬磁盤(pán)426.7%

6公司現(xiàn)行方案(2+3+4+5)980%

7黑蘋(píng)果588.9%

8終極方案(1+2+3+5+7)4(預(yù)計(jì))91.1%(預(yù)計(jì))

嚴(yán)格意義上講女轿,文章有點(diǎn)標(biāo)題黨了箭启,因?yàn)橐痪湓拋?lái)說(shuō)就是:

能用硬件解決的問(wèn)題,就不要用軟件解決蛉迹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末傅寡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子北救,更是在濱河造成了極大的恐慌荐操,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件珍策,死亡現(xiàn)場(chǎng)離奇詭異托启,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)膛壹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)驾中,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)唉堪,“玉大人,你說(shuō)我怎么就攤上這事肩民∵胙牵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵持痰,是天一觀的道長(zhǎng)灶搜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)工窍,這世上最難降的妖魔是什么割卖? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮患雏,結(jié)果婚禮上鹏溯,老公的妹妹穿的比我還像新娘。我一直安慰自己淹仑,他們只是感情好丙挽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著匀借,像睡著了一般颜阐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吓肋,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天凳怨,我揣著相機(jī)與錄音,去河邊找鬼是鬼。 笑死肤舞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的屑咳。 我是一名探鬼主播萨赁,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼兆龙!你這毒婦竟也來(lái)了杖爽?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤紫皇,失蹤者是張志新(化名)和其女友劉穎慰安,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體聪铺,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡化焕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铃剔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撒桨。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡查刻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出凤类,到底是詐尸還是另有隱情穗泵,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布谜疤,位于F島的核電站佃延,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏夷磕。R本人自食惡果不足惜履肃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坐桩。 院中可真熱鬧尺棋,春花似錦、人聲如沸撕攒。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)抖坪。三九已至,卻和暖如春闷叉,著一層夾襖步出監(jiān)牢的瞬間擦俐,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工握侧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蚯瞧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓品擎,卻偏偏與公主長(zhǎng)得像埋合,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子萄传,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容