微信的并發(fā)編程(轉(zhuǎn):采用協(xié)程技術(shù))

如今十绑,微信擁有月活躍用戶8億。

不可否認(rèn)酷勺,當(dāng)今的微信后臺(tái)擁有著強(qiáng)大的并發(fā)能力本橙。

不過(guò), 正如羅馬并非一日建成鸥印;微信的技術(shù)也曾經(jīng)略顯稚嫩。

微信誕生于2011年1月坦报,當(dāng)年用戶規(guī)模為0.1億左右库说;2013年11月,微信月活躍用戶數(shù)達(dá)到3.55億片择,一躍成為亞洲地區(qū)擁有最大用戶群體的移動(dòng)終端即時(shí)通訊軟件潜的。

面對(duì)如此體量的提升,微信后臺(tái)也曾遭遇棘手的窘境谨敛;令人贊嘆的是技術(shù)人及時(shí)地做出了漂亮的應(yīng)對(duì)眶熬。

這背后有著怎樣的技術(shù)故事悼沈?

此時(shí)此刻,你在微信手機(jī)端發(fā)出的請(qǐng)求亡呵,是怎樣被后臺(tái)消化和處理的?

這次硫戈,InfoQ聚焦微信后臺(tái)解決方案之協(xié)程庫(kù)libco锰什。

該項(xiàng)目在保留后臺(tái)敏捷的同步風(fēng)格同時(shí),提高了系統(tǒng)的并發(fā)能力丁逝,節(jié)省了大量的服務(wù)器成本汁胆;自2013年起穩(wěn)定運(yùn)行于微信的數(shù)萬(wàn)臺(tái)機(jī)器之上。

本文源自InfoQ對(duì)Leiffy的采訪和《揭秘:微信如何用libco支撐8億用戶》的整理霜幼。
微信后端遇到了問(wèn)題

早期微信后臺(tái)因?yàn)闃I(yè)務(wù)需求復(fù)雜多變嫩码、產(chǎn)品要求快速迭代等需求,大部分模塊都采用了半同步半異步模型罪既。接入層為異步模型铸题,業(yè)務(wù)邏輯層則是同步的多進(jìn)程或多線程模型铡恕,業(yè)務(wù)邏輯的并發(fā)能力只有幾十到幾百。

隨著微信業(yè)務(wù)的增長(zhǎng)回挽,直到2013年中没咙,微信后臺(tái)機(jī)器規(guī)模已達(dá)到1萬(wàn)多臺(tái),涉及數(shù)百個(gè)后臺(tái)模塊千劈,RPC調(diào)用每分鐘數(shù)十億祭刚。在如此龐大復(fù)雜的系統(tǒng)規(guī)模下,每個(gè)模塊很容易受到后端服務(wù)或者網(wǎng)絡(luò)抖動(dòng)的影響墙牌。因此我們急需對(duì)微信后臺(tái)進(jìn)行異步化的改造涡驮。
異步化改造方案的考量

當(dāng)時(shí)我們有兩種選擇:

A 線程異步化:把所有服務(wù)改造成異步模型,等同于從框架到業(yè)務(wù)邏輯代碼的徹底改造
B 協(xié)程異步化:對(duì)業(yè)務(wù)邏輯非侵入的異步化改造喜滨,即只修該少量框架代碼

兩者相比捉捅,工作量和風(fēng)險(xiǎn)系數(shù)的差異顯而易見(jiàn)。雖然A方案服務(wù)器端多線程異步處理是常見(jiàn)做法虽风,對(duì)提高并發(fā)能力這個(gè)原始目標(biāo)非常奏效棒口;但是對(duì)于微信后臺(tái)如此復(fù)雜的系統(tǒng),這過(guò)于耗時(shí)耗力且風(fēng)險(xiǎn)巨大辜膝。

無(wú)論是異步模型還是同步模型无牵,都需要保存異步狀態(tài)。所以兩者在技術(shù)細(xì)節(jié)的相同點(diǎn)是厂抖,兩個(gè)方案茎毁,都是需要維護(hù)當(dāng)前請(qǐng)求的狀態(tài)。在A異步模型中方案忱辅,當(dāng)請(qǐng)求需要被異步執(zhí)行時(shí)七蜘,需要主動(dòng)把請(qǐng)求相關(guān)數(shù)據(jù)保存起來(lái),再等待狀態(tài)機(jī)的下一次調(diào)度執(zhí)行墙懂;而在B協(xié)程模型方案中橡卤,異步狀態(tài)的保存與恢復(fù)是自動(dòng)的,協(xié)程恢復(fù)執(zhí)行的時(shí)候就是上一次退出時(shí)的上下文损搬。

因此蒜魄,B協(xié)程方案不需要顯式地維護(hù)異步狀態(tài):一方面在編程上可以更簡(jiǎn)單和直接;另一方面協(xié)程中只需要保存少量的寄存器场躯。因此在復(fù)雜系統(tǒng)上谈为,協(xié)程服務(wù)的性能可能比純異步模型更優(yōu)。

綜合以上考慮踢关,最終我們選擇了B方案伞鲫,通過(guò)協(xié)程的方式對(duì)微信后臺(tái)上百個(gè)模塊進(jìn)行了異步化改造。
接管歷史遺留的同步風(fēng)格API

方案敲定之后签舞,接下來(lái)做的就是實(shí)現(xiàn)異步化的同時(shí)盡可能地少做代碼修改秕脓。

通常而言柒瓣,一個(gè)常規(guī)的網(wǎng)絡(luò)后臺(tái)服務(wù)需要connect、write吠架、read等系列步驟芙贫,如果使用同步風(fēng)格的API對(duì)網(wǎng)絡(luò)進(jìn)行調(diào)用,整個(gè)服務(wù)線程會(huì)因?yàn)榈却W(wǎng)絡(luò)交互而掛起傍药,這就會(huì)造成等待并占用資源磺平。原來(lái)的這種情況很明顯地影響到了系統(tǒng)的并發(fā)性能,但是當(dāng)初這樣的選擇是因?yàn)閷?duì)應(yīng)的同步編程風(fēng)格具有其獨(dú)特的優(yōu)勢(shì):代碼邏輯清晰拐辽、易于編寫(xiě)并且支持業(yè)務(wù)快速迭代敏捷開(kāi)發(fā)拣挪。

我們的改造方案需要消除同步風(fēng)格API的缺點(diǎn),但是同時(shí)還希望保持同步編程的優(yōu)點(diǎn)俱诸。

最后在不修改線上已有的業(yè)務(wù)邏輯代碼的情況下菠劝,我們的libco框架創(chuàng)新地接管了網(wǎng)絡(luò)調(diào)用接口(Hook)。把協(xié)程的讓出與恢復(fù)作為異步網(wǎng)絡(luò)IO中的一次事件注冊(cè)與回調(diào)睁搭。當(dāng)業(yè)務(wù)處理遇到同步網(wǎng)絡(luò)請(qǐng)求的時(shí)候赶诊,libco層會(huì)把本次網(wǎng)絡(luò)請(qǐng)求注冊(cè)為異步事件,當(dāng)前的協(xié)程讓出CPU占用园骆,CPU交給其它協(xié)程執(zhí)行舔痪。在網(wǎng)絡(luò)事件發(fā)生或者超時(shí)的時(shí)候,libco會(huì)自動(dòng)的恢復(fù)協(xié)程執(zhí)行遇伞。
libco的架構(gòu)

libco架構(gòu)從設(shè)計(jì)的時(shí)候就已經(jīng)確立下來(lái)了辙喂,最近的在GitHub上一次較大更新主要是功能上的更新捶牢。(注:libco為開(kāi)源項(xiàng)目鸠珠,源碼同步更新,可移步:https://github.com/tencent/libco)秋麸。

libco框架有三層:分別是協(xié)程接口層渐排、系統(tǒng)函數(shù)Hook層以及事件驅(qū)動(dòng)層。

協(xié)程接口層實(shí)現(xiàn)了協(xié)程的基本源語(yǔ)灸蟆。co_create驯耻、co_resume等簡(jiǎn)單接口負(fù)責(zé)協(xié)程創(chuàng)建于恢復(fù)。co_cond_signal類(lèi)接口可以在協(xié)程間創(chuàng)建一個(gè)協(xié)程信號(hào)量炒考,可用于協(xié)程間的同步通信可缚。

系統(tǒng)函數(shù)Hook層負(fù)責(zé)主要負(fù)責(zé)系統(tǒng)中同步API到異步執(zhí)行的轉(zhuǎn)換。對(duì)于常用的同步網(wǎng)絡(luò)接口斋枢,Hook層會(huì)把本次網(wǎng)絡(luò)請(qǐng)求注冊(cè)為異步事件帘靡,然后等待事件驅(qū)動(dòng)層的喚醒執(zhí)行。

事件驅(qū)動(dòng)層實(shí)現(xiàn)了一個(gè)簡(jiǎn)單高效的異步網(wǎng)路框架瓤帚,里面包含了異步網(wǎng)絡(luò)框架所需要的事件與超時(shí)回調(diào)描姚。對(duì)于來(lái)源于同步系統(tǒng)函數(shù)Hook層的請(qǐng)求涩赢,事件注冊(cè)與回調(diào)實(shí)質(zhì)上是協(xié)程的讓出與恢復(fù)執(zhí)行。
相比線程轩勘,選擇協(xié)程意味著筒扒?

比起線程,對(duì)于很多人而言绊寻,協(xié)程的應(yīng)用并不是那么輕車(chē)熟路花墩。

線程和協(xié)程的相同點(diǎn)是什么?

我們可以簡(jiǎn)單認(rèn)為協(xié)程是一種用戶態(tài)線程榛斯,它與線程一樣擁有獨(dú)立的寄存器上下文以及運(yùn)行棧观游,對(duì)程序員最直觀的效果就是,代碼可以在協(xié)程里面正常的運(yùn)作驮俗,就像在線程里面一樣懂缕。但是線程和協(xié)程還是有區(qū)別的,我們需要重點(diǎn)關(guān)注是運(yùn)行棧管理模式與協(xié)程調(diào)度策略王凑。關(guān)于這兩點(diǎn)的具體執(zhí)行搪柑,在本文后續(xù)部分會(huì)談及。

那兩者的不同點(diǎn)呢索烹?

協(xié)程的創(chuàng)建與調(diào)度相比線程要輕量得多工碾,而且協(xié)程間的通信與同步是可以無(wú)鎖的,任一時(shí)刻都可以保證只有本協(xié)程在操作線程內(nèi)的資源百姓。

我們的方案是使用協(xié)程渊额,但這意味著面臨以下挑戰(zhàn):

業(yè)界協(xié)程在C/C++環(huán)境下沒(méi)有大規(guī)模應(yīng)用的經(jīng)驗(yàn);
如何處理同步風(fēng)格的API調(diào)用,如Socket垒拢、mysqlclient等; 
如何控制協(xié)程調(diào)度;
如何處理已有全局變量旬迹、線程私有變量的使用;

下面我們來(lái)探討如何攻克這四個(gè)挑戰(zhàn)。
挑戰(zhàn)之一:前所未有的大規(guī)模應(yīng)用C/C++協(xié)程

實(shí)際上求类,協(xié)程這個(gè)概念的確很早就提出來(lái)了奔垦,但是確是因?yàn)樽罱鼛啄暝谀承┱Z(yǔ)言中(如lua、go等)被廣泛的應(yīng)用而逐漸的被大家所熟知尸疆。但是真正用于C/C++語(yǔ)言的椿猎、并且是大規(guī)模生產(chǎn)的著實(shí)不多。

而這個(gè)libco框架中寿弱,除了協(xié)程切換時(shí)寄存器保存與恢復(fù)使用了匯編代碼犯眠,其它代碼實(shí)現(xiàn)都是用C/C++語(yǔ)言編寫(xiě)的。

那為什么我們選擇了C/C++語(yǔ)言症革?

當(dāng)前微信后臺(tái)絕大部分服務(wù)都基于C++筐咧,原因是微信最早的后臺(tái)開(kāi)發(fā)團(tuán)隊(duì)從郵箱延續(xù)而來(lái),郵箱團(tuán)隊(duì)一直使用C++作為后臺(tái)主流開(kāi)發(fā)語(yǔ)言地沮,而且C++能滿足微信后臺(tái)對(duì)性能和穩(wěn)定性的要求嗜浮。

我們的C++后臺(tái)服務(wù)框架增加了協(xié)程支持之后羡亩,高并發(fā)和快速開(kāi)發(fā)的矛盾解決了。開(kāi)發(fā)者絕大部分情況下只需要關(guān)注并發(fā)數(shù)的配置危融,不需要關(guān)注協(xié)程本身畏铆。其他語(yǔ)言我們也會(huì)在一些工具里面嘗試,但是對(duì)于整個(gè)微信后臺(tái)而言吉殃,C++仍是我們未來(lái)長(zhǎng)期的主流語(yǔ)言辞居。
挑戰(zhàn)之二:保留同步風(fēng)格的API

這里的做法我們?cè)谏衔闹刑岬搅颂幚硗斤L(fēng)格的API的思路方法:大部分同步風(fēng)格的API我們都通過(guò)Hook的方法來(lái)接管了,libco會(huì)在恰當(dāng)?shù)臅r(shí)機(jī)調(diào)度協(xié)程恢復(fù)執(zhí)行蛋勺。

怎樣防止協(xié)程庫(kù)調(diào)度器被阻塞瓦灶?

libco的系統(tǒng)函數(shù)Hook層主要處理同步API到異步執(zhí)行的轉(zhuǎn)換,我們當(dāng)前的hook層只處理了主要的同步網(wǎng)絡(luò)接口抱完,對(duì)于這些接口贼陶,同步調(diào)用會(huì)被異步執(zhí)行,不會(huì)導(dǎo)致系統(tǒng)的線程阻塞巧娱。當(dāng)然碉怔,我們還有少量未Hook的同步接口,這些接口的調(diào)用可能會(huì)導(dǎo)致協(xié)程調(diào)度器阻塞等待禁添。

與線程類(lèi)似撮胧,當(dāng)我們操作跨線程數(shù)據(jù)的時(shí)候,需要使用線程安全級(jí)別的函數(shù)老翘。而在協(xié)程環(huán)境下芹啥,也是有協(xié)程安全的代碼約束。在微信后臺(tái)铺峭,我們約束了不能使用導(dǎo)致協(xié)程阻塞的函數(shù)墓怀,比如pthread_mutex、sleep類(lèi)函數(shù)(可以用poll(NULL, 0, timeout) 代替)等逛薇。而對(duì)于已有系統(tǒng)的改造捺疼,就需要審核已有代碼是否符合協(xié)程安全規(guī)范疏虫。
挑戰(zhàn)之三:調(diào)度千萬(wàn)級(jí)協(xié)程

調(diào)度策略方面永罚,我們可以看下Linux的進(jìn)程調(diào)度,從早期的O(1)到目前CFS完全公平調(diào)度卧秘,經(jīng)過(guò)了很復(fù)雜的演進(jìn)過(guò)程呢袱,而協(xié)程調(diào)度事實(shí)上也是可以參考進(jìn)程調(diào)度方法的,比如說(shuō)你可以定義一種調(diào)度策略翅敌,使得協(xié)程在不同的線程間切換羞福,但是這樣做會(huì)帶來(lái)昂貴的切換代價(jià)。在進(jìn)程/線程上面蚯涮,后臺(tái)服務(wù)通常已經(jīng)做了足夠多的工作治专,使得多核資源得到充分使用卖陵,所以協(xié)程的定位應(yīng)該是在這個(gè)基礎(chǔ)上發(fā)揮最大的性能。

libco的協(xié)程調(diào)度策略很簡(jiǎn)潔张峰,單個(gè)協(xié)程限定在固定的線程內(nèi)部泪蔫,僅在網(wǎng)絡(luò)IO阻塞等待時(shí)候切出,在網(wǎng)絡(luò)IO事件觸發(fā)時(shí)候切回喘批,也就是說(shuō)在這個(gè)層面上面可以認(rèn)為協(xié)程就是有限狀態(tài)機(jī)撩荣,在事件驅(qū)動(dòng)的線程里面工作,相信后臺(tái)開(kāi)發(fā)的同學(xué)會(huì)一下子就明白了饶深。

那怎么實(shí)現(xiàn)千萬(wàn)級(jí)別呢餐曹?

libco默認(rèn)是每一個(gè)協(xié)程獨(dú)享一個(gè)運(yùn)行棧,在協(xié)程創(chuàng)建的時(shí)候敌厘,從堆內(nèi)存分配一個(gè)固定大小的內(nèi)存作為該協(xié)程的運(yùn)行棧台猴。如果我們用一個(gè)協(xié)程處理前端的一個(gè)接入連接,那對(duì)于一個(gè)海量接入服務(wù)來(lái)說(shuō)俱两,我們的服務(wù)的并發(fā)上限就很容易受限于內(nèi)存卿吐。

所以量級(jí)的問(wèn)題就轉(zhuǎn)換成了怎樣高效使用內(nèi)存的問(wèn)題。

為了解決這個(gè)問(wèn)題锋华,libco采用的是共享?xiàng)DJ轿斯佟#▊鹘y(tǒng)運(yùn)行棧管理有stackfull和stackless兩種模式)簡(jiǎn)單來(lái)講,是若干個(gè)協(xié)程共享同一個(gè)運(yùn)行棧毯焕。

同一個(gè)共享?xiàng)O碌膮f(xié)程間切換的時(shí)候衍腥,需要把當(dāng)前的運(yùn)行棧內(nèi)容拷貝到協(xié)程的私有內(nèi)存中。為了減少這種內(nèi)存拷貝次數(shù)纳猫,共享?xiàng)5膬?nèi)存拷貝只發(fā)生在不同協(xié)程間的切換婆咸。當(dāng)共享?xiàng)5恼加谜咭恢睕](méi)有改變的時(shí)候,則不需要拷貝運(yùn)行棧芜辕。

再具體一點(diǎn)講講共享?xiàng)5脑恚簂ibco默認(rèn)模式(stackfull) 滿足大部分的業(yè)務(wù)場(chǎng)景尚骄,每個(gè)協(xié)程獨(dú)占128k棧空間侵续,只需1G內(nèi)存就可以支持萬(wàn)級(jí)協(xié)程倔丈。 而共享?xiàng)J莑ibco新增的一個(gè)特性,可以支持單機(jī)千萬(wàn)協(xié)程状蜗,應(yīng)對(duì)海量連接特殊場(chǎng)景需五。實(shí)現(xiàn)原理上,共享?xiàng)DJ皆趥鹘y(tǒng)的stackfull和stackless兩種模式之間做了個(gè)微創(chuàng)新轧坎,用戶可以自定義分配若干個(gè)共享?xiàng)?nèi)存宏邮,協(xié)程創(chuàng)建時(shí)指定使用哪一個(gè)共享?xiàng)!?/p>

不同協(xié)程之間的切換、 如何主動(dòng)退出一個(gè)正在執(zhí)行的協(xié)程蜜氨?我們把共享同一塊棧內(nèi)存的多個(gè)協(xié)程稱為協(xié)程組械筛,協(xié)程組內(nèi)不同協(xié)程之間切換需要把棧內(nèi)存拷貝到協(xié)程的私有空間,而協(xié)程組內(nèi)同一個(gè)協(xié)程的讓出與恢復(fù)執(zhí)行則不需要拷貝棧內(nèi)存飒炎,可以認(rèn)為共享?xiàng)5臈?nèi)存是“寫(xiě)時(shí)拷貝”的变姨。

共享?xiàng)O碌膮f(xié)程切換與退出,與普通協(xié)程模式的API一致厌丑,co_yield與co_resume定欧,libco底層會(huì)實(shí)現(xiàn)共享?xiàng)5哪J较碌陌葱杩截悧?nèi)存。
挑戰(zhàn)之四:全局變量 VS私有變量

在stackfull模式下面怒竿,局部變量的地址是一直不變的砍鸠;而stackless模式下面,只要協(xié)程被切出耕驰,那么局部變量的地址就失效了爷辱,這是開(kāi)發(fā)者需要注意的地方。

libco默認(rèn)的棧模式是每一個(gè)協(xié)程獨(dú)享運(yùn)行棧的朦肘,在這個(gè)模式下饭弓,開(kāi)發(fā)者需要注意棧內(nèi)存的使用,盡量避免 char buf[128 * 1024] 這種超大棧變量的申請(qǐng)媒抠,當(dāng)棧使用大小超過(guò)本協(xié)程棧大小的時(shí)候弟断,就可能導(dǎo)致棧溢出的core。

而在共享?xiàng)DJ较屡可m然在協(xié)程創(chuàng)建的時(shí)候可以映射到一個(gè)比較大的棧內(nèi)存上面阀趴,但是當(dāng)本協(xié)程需要讓出給其它協(xié)程執(zhí)行的時(shí)候,已使用棧的拷貝保存開(kāi)銷(xiāo)也是有的苍匆,因此最好也是盡量減少大的局部變量使用刘急。更多的,共享?xiàng)DJ较陆龋驗(yàn)槭嵌鄠€(gè)協(xié)程共享了同一個(gè)検逯空間,因此检碗,用戶需要注意協(xié)程內(nèi)的局部棧變量地址不可以跨協(xié)程傳遞据块。

協(xié)程私有變量的使用場(chǎng)景與線程私有變量類(lèi)似,協(xié)程私有變量是全局可見(jiàn)的后裸,不同的協(xié)程會(huì)對(duì)同一個(gè)協(xié)程變量保存自己的副本瑰钮。開(kāi)發(fā)者可以通過(guò)我們的API宏聲明協(xié)程私有變量冒滩,在使用上無(wú)特別需要注意的地方微驶。

多進(jìn)程程序改造為多線程程序時(shí)候,我們可以用__thread來(lái)對(duì)全局變量進(jìn)行快速修改,而在協(xié)程環(huán)境下因苹,我們創(chuàng)造了協(xié)程變量ROUTINE_VAR苟耻,極大簡(jiǎn)化了協(xié)程的改造工作量。

關(guān)于協(xié)程私有變量扶檐,因?yàn)閰f(xié)程實(shí)質(zhì)上是線程內(nèi)串行執(zhí)行的凶杖,所以當(dāng)我們定義了一個(gè)線程私有變量的時(shí)候,可能會(huì)有重入的問(wèn)題款筑。比如我們定義了一個(gè)__thread的線程私有變量智蝠,原本是希望每一個(gè)執(zhí)行邏輯獨(dú)享這個(gè)變量的。但當(dāng)我們的執(zhí)行環(huán)境遷移到協(xié)程了之后奈梳,同一個(gè)線程私有變量杈湾,可能會(huì)有多個(gè)協(xié)程會(huì)操作它,這就導(dǎo)致了變量沖入的問(wèn)題攘须。為此漆撞,我們?cè)谧鰈ibco異步化改造的時(shí)候,把大部分的線程私有變量改成了協(xié)程級(jí)私有變量于宙。協(xié)程私有變量具有這樣的特性:當(dāng)代碼運(yùn)行在多線程非協(xié)程環(huán)境下時(shí)浮驳,該變量是線程私有的;當(dāng)代碼運(yùn)行在協(xié)程環(huán)境的時(shí)候捞魁,此變量是協(xié)程私有的至会。底層的協(xié)程私有變量會(huì)自動(dòng)完成運(yùn)行環(huán)境的判斷并正確返回所需的值。

協(xié)程私有變量對(duì)于現(xiàn)有環(huán)境同步到異步化改造起了舉足輕重的作用谱俭,同時(shí)我們定義了一個(gè)非常簡(jiǎn)單方便的方法定義協(xié)程私有變量奋献,簡(jiǎn)單到只需一行聲明代碼即可。
簡(jiǎn)而言之

一句話總結(jié)libco庫(kù)的原理旺上,在協(xié)程里面用同步風(fēng)格編寫(xiě)代碼瓶蚂,實(shí)際運(yùn)作是事件驅(qū)動(dòng)的有限狀態(tài)機(jī),由上層的進(jìn)程/線程負(fù)責(zé)多核資源的使用宣吱。
最終效果窃这,大功告成

我們?cè)岩粋€(gè)狀態(tài)機(jī)驅(qū)動(dòng)的純異步代理服務(wù)改成了基于libco協(xié)程的服務(wù),在性能上比之前提升了10%到20%征候,并且杭攻,在基于協(xié)程的同步模型下,我們很簡(jiǎn)單的就實(shí)現(xiàn)了批量請(qǐng)求的功能疤坝。

正如當(dāng)時(shí)所愿兆解,我們使用libco對(duì)微信后臺(tái)上百個(gè)模塊進(jìn)行了協(xié)程異步化改造,在整個(gè)的改造過(guò)程中跑揉,業(yè)務(wù)邏輯代碼基本沒(méi)有改變锅睛,修改只是在框架層代碼埠巨。我們所做的是把原先在線程內(nèi)執(zhí)行的業(yè)務(wù)邏輯轉(zhuǎn)到了協(xié)程上執(zhí)行。改造的工作主要是復(fù)核系統(tǒng)中線程私有變量现拒、全局變量辣垒、線程鎖的使用,確保在協(xié)程切換的時(shí)候不會(huì)數(shù)據(jù)錯(cuò)亂或者重入印蔬。

至今勋桶,微信后臺(tái)絕大部分服務(wù)都已是多進(jìn)程或多線程協(xié)程模型,并發(fā)能力相比之前有了質(zhì)的提升侥猬,而在這過(guò)程中應(yīng)運(yùn)而生的libco也成為了微信后臺(tái)框架的基石例驹。
作者簡(jiǎn)介

李方源, 微信高級(jí)工程師,目前負(fù)責(zé)微信后臺(tái)基礎(chǔ)框架及優(yōu)化退唠,致力于高性能眠饮、高可用的大規(guī)模分布式系統(tǒng)設(shè)計(jì)及研發(fā),先后參與微信后臺(tái)協(xié)程化改造項(xiàng)目铜邮、微信后臺(tái)框架重構(gòu)等項(xiàng)目仪召。

libco為開(kāi)源項(xiàng)目,源碼同步更新松蒜,可移步: https://github.com/tencent/libco

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扔茅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子秸苗,更是在濱河造成了極大的恐慌召娜,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惊楼,死亡現(xiàn)場(chǎng)離奇詭異玖瘸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)檀咙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)雅倒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人弧可,你說(shuō)我怎么就攤上這事蔑匣。” “怎么了棕诵?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵裁良,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我校套,道長(zhǎng)价脾,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任笛匙,我火速辦了婚禮侨把,結(jié)果婚禮上犀变,老公的妹妹穿的比我還像新娘。我一直安慰自己座硕,他們只是感情好弛作,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布涕蜂。 她就那樣靜靜地躺著华匾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪机隙。 梳的紋絲不亂的頭發(fā)上蜘拉,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音有鹿,去河邊找鬼旭旭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛葱跋,可吹牛的內(nèi)容都是我干的持寄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼娱俺,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼稍味!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起荠卷,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤模庐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后油宜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體掂碱,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年慎冤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疼燥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚁堤,死狀恐怖悴了,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情违寿,我是刑警寧澤湃交,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站藤巢,受9級(jí)特大地震影響搞莺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜掂咒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一才沧、第九天 我趴在偏房一處隱蔽的房頂上張望迈喉。 院中可真熱鬧,春花似錦温圆、人聲如沸挨摸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)得运。三九已至,卻和暖如春锅移,著一層夾襖步出監(jiān)牢的瞬間熔掺,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工非剃, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留置逻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓备绽,卻偏偏與公主長(zhǎng)得像券坞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肺素,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,101評(píng)論 1 32
  • 輕量級(jí)線程:協(xié)程 在常用的并發(fā)模型中压怠,多進(jìn)程眠冈、多線程、分布式是最普遍的菌瘫,不過(guò)近些年來(lái)逐漸有一些語(yǔ)言以first-c...
    Tenderness4閱讀 6,364評(píng)論 2 10
  • 你的第一個(gè)協(xié)程 輸出結(jié)果 從本質(zhì)上講蜗顽,協(xié)同程序是輕量級(jí)的線程。它們是與發(fā)布 協(xié)同程序構(gòu)建器一起啟動(dòng)的雨让。您可以實(shí)現(xiàn)相...
    十方天儀君閱讀 2,509評(píng)論 0 2
  • 第1章 并發(fā)編程的挑戰(zhàn) 1.1 上下文切換 即便是單核CPU也支持多線程并發(fā)雇盖,CPU通過(guò)給每個(gè)線程分配時(shí)間片(幾十...
    卑鄙的鹿尤菌閱讀 4,766評(píng)論 1 22
  • 1. cpu通過(guò)時(shí)間片分配算法來(lái)循環(huán)執(zhí)行任務(wù),當(dāng)前任務(wù)執(zhí)行一個(gè)時(shí)間片后會(huì)切換到下一任務(wù)栖忠。但是崔挖,再切換之前會(huì)保存上一...
    冰與河豚魚(yú)閱讀 668評(píng)論 0 0