復(fù)雜網(wǎng)絡(luò)大師賽第四名技術(shù)分享(篇二:工程技巧的勝利溶耘、附代碼)

0x00 背景

(代碼見文末)

在上一篇文章《復(fù)雜網(wǎng)絡(luò)大師賽第四名技術(shù)分享(篇一:思路與分析)》中二拐,我們大概介紹了一下這次復(fù)雜網(wǎng)絡(luò)大師賽的基本情況,并簡要的分析了官方的評價(jià)算法和我自己的思路凳兵。其中很重要的一個(gè)環(huán)節(jié)就是利用官方的評價(jià)算法來優(yōu)化節(jié)點(diǎn)重要性的序列百新,但是這個(gè)方法有一個(gè)硬傷,就是對評價(jià)算法的效率要求非常高庐扫。而官方提供的groovy版本僅僅用來計(jì)算魯棒值還好饭望,如果想在它的基礎(chǔ)上進(jìn)行改造,用于尋找更優(yōu)的序列就有點(diǎn)不切實(shí)際了形庭。

提到高效铅辞,相信很多人第一個(gè)想到的就是C/C++,的確萨醒,單從效率上來看斟珊,眾多編程語言無出其右者。但是運(yùn)行效率和開發(fā)效率似乎是一對天生的冤家富纸,運(yùn)行效率上去了囤踩,必然會(huì)導(dǎo)致在開發(fā)和程序優(yōu)化上耗費(fèi)大量的時(shí)間。C語言雖然是很多人的最先學(xué)習(xí)的編程語言晓褪,卻很少人敢拍著胸脯說自己能很好的駕馭它堵漱,尤其涉及到一些內(nèi)存和程序優(yōu)化相關(guān)的問題,如果在不熟悉的情況下硬上涣仿,可能最后的運(yùn)行效率還比不上Java或者Python怔锌,“辱沒”了C語言的美名。

本文就來講講我在用C語言實(shí)現(xiàn)官方的評價(jià)算法時(shí)踩過的坑变过,以及我是如何思考并一個(gè)一個(gè)的解決這些問題的埃元。正是依靠這個(gè)高效的工程實(shí)現(xiàn),將我的排名從二十多一路刷到第四媚狰,所以我厚顏無恥的稱之為“工程技巧的勝利”……當(dāng)然岛杀,如果你是資深的C/C++攻城獅,就權(quán)當(dāng)看看故事會(huì)吧崭孤。

0x01 STL的坑类嗤?

一開始由于我對純C還是抱有一絲敬畏之心(其實(shí)就是怕麻煩),而且想當(dāng)然的認(rèn)為C++的效率也差不到哪去辨宠,所以決定先用C++寫一版遗锣。

回顧一下上一篇文章對評價(jià)算法的描述,我們需要用到clusters來存儲(chǔ)所有的集群和集群中的成員嗤形。先腦補(bǔ)一下變量clusters理論上的存儲(chǔ)結(jié)構(gòu)精偿,如下圖所示

[圖片上傳失敗...(image-e1a222-1514533769166)]

注意,圖中每一個(gè)小的cluster應(yīng)該都是可動(dòng)態(tài)變化的數(shù)組,能夠添加指定個(gè)數(shù)的節(jié)點(diǎn)(在cluster合并時(shí)需要加入多個(gè)節(jié)點(diǎn))笔咽,看看官方的groovy版本是如何實(shí)現(xiàn)的搔预,截取其中的一個(gè)代碼片段,如下所示

[圖片上傳失敗...(image-eb5b18-1514533769167)]

其中叶组,變量sumList對應(yīng)我們算法描述中的clusters拯田,變量vMap對應(yīng)算法描述中的node_clusterid,從變量定義中可以看出來甩十,這里是用了HashMap數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)所有集團(tuán)及其集團(tuán)成員船庇。其中Integer對應(yīng)了集團(tuán)ID號,而HashSet<Integer>則用于存儲(chǔ)該集團(tuán)中的成員(也就是節(jié)點(diǎn)ID號)侣监。

當(dāng)然溢十,C++里是沒有HashMap或者HashSet這種數(shù)據(jù)結(jié)構(gòu)的,不過好在C++的STL中倒是有諸如unordered_mapvector這樣的容器达吞。于是乎斤斧,我依靠C++的文檔难衰,照著官方的groovy代碼將評價(jià)算法實(shí)現(xiàn)了一遍交胚,期間踩坑無數(shù)潘悼。當(dāng)我好不容易排除所有bug独郎,滿懷激動(dòng)的編譯執(zhí)行時(shí)壁查,現(xiàn)實(shí)卻狠狠的給了我一記悶棍猛遍。即使是計(jì)算規(guī)模最小的40萬節(jié)點(diǎn)的網(wǎng)絡(luò)魯棒值育灸,程序跑到一半竟然就慢如蝸牛遮咖,過了5分鐘都沒有出結(jié)果滩字,用C++寫的程序效率竟然比不過Java?無奈之下御吞,只得強(qiáng)行結(jié)束進(jìn)程查找原因麦箍。

經(jīng)過一番搜索,我大概找出了導(dǎo)致程序運(yùn)行緩慢的原因陶珠,問題集中在vector的使用上:

  1. 第一個(gè)問題是我初始化vector的形式挟裂,考慮到集團(tuán)是動(dòng)態(tài)變化的,所以我沒有在初始化的時(shí)候指定它的大小揍诽。而網(wǎng)上很多資料都提到诀蓉,應(yīng)該盡量在一開始就給vector分配足夠的空間,用vector.reserve()可以實(shí)現(xiàn)暑脆。
  2. 第二個(gè)問題其實(shí)與第一個(gè)問題相關(guān)渠啤,就是向vector中添加元素的方式,我使用的是vector.push_back(vi)添吗,而網(wǎng)上的資料說的非常明確沥曹,push_back的效率非常低下,原因在于push_back會(huì)先做一步越界檢查,即使vector的空間足夠架专。而高效的做法是在確保不越界的情況下同窘,用類似vector[i]=vi的方式實(shí)現(xiàn)。

也就是說部脚,為了提高效率想邦,我們應(yīng)該盡量提前給vector申請好足夠的存儲(chǔ)空間,并利用指針?biāo)饕姆绞讲迦朐匚酢丧没?墒菃栴}來了,集團(tuán)大小都是動(dòng)態(tài)變化的锡移,我們?nèi)绾翁崆邦A(yù)知某個(gè)集團(tuán)應(yīng)該預(yù)留多少空間呢呕童?

那么,索性給每個(gè)集團(tuán)都預(yù)留足夠的空間:將每個(gè)vector的大小都設(shè)置為該網(wǎng)絡(luò)中所有節(jié)點(diǎn)的數(shù)量淆珊,這樣就可以放心的使用指針?biāo)饕姆绞讲迦牒妥x取元素夺饲,而不用擔(dān)心越界的問題了。

0x02 內(nèi)存不足施符?

按照剛才的思路往声,對上一版程序稍作修改之后,興奮的編譯執(zhí)行戳吝,卻再次被現(xiàn)實(shí)打臉浩销,程序提示內(nèi)存不足。為什么會(huì)這樣听哭?我們來做一個(gè)簡單的計(jì)算慢洋,以規(guī)模為40萬節(jié)點(diǎn)的網(wǎng)絡(luò)為例,假設(shè)用int表示節(jié)點(diǎn)ID號陆盘,存儲(chǔ)一個(gè)40萬節(jié)點(diǎn)大小的集團(tuán)所需要的空間大約為4*4*100000字節(jié)普筹,約1.53MB左右,如果網(wǎng)絡(luò)中有1萬個(gè)度為1的節(jié)點(diǎn)(這已經(jīng)是非常保守的估計(jì)了隘马,實(shí)際還要比這多)斑芜,也就意味著在算法的初期總共要開辟1.53*100000 MB的空間,約14.94GB祟霍,這還僅僅是規(guī)模最小的網(wǎng)絡(luò)的保守估計(jì)杏头,對其他200萬節(jié)點(diǎn)規(guī)模的網(wǎng)絡(luò),所需的內(nèi)存量無疑是天文數(shù)字沸呐。因此醇王,這種粗放暴力的內(nèi)存申請方式顯然是要不得的。

可是這樣就陷入了兩難的處境崭添,提前分配足夠的vector空間會(huì)導(dǎo)致內(nèi)存不足寓娩。若不提前給vector分配好內(nèi)存空間,就要?jiǎng)討B(tài)的擴(kuò)展vector大小而嚴(yán)重影響效率。

權(quán)衡之下棘伴,我決定放棄使用C++的vector存儲(chǔ)集團(tuán)成員寞埠,轉(zhuǎn)而采用C語言中數(shù)組存儲(chǔ),并用malloc方式動(dòng)態(tài)申請內(nèi)存焊夸。

0x03 詭異的Bug

有的同學(xué)可能會(huì)問仁连,用malloc申請的數(shù)組長度不是固定的么,能夠滿足動(dòng)態(tài)擴(kuò)展的需求嗎阱穗?當(dāng)然是可以的饭冬,有兩種實(shí)現(xiàn)方式:第一種是用realloc函數(shù),另一種是重新malloc一塊更大的內(nèi)存揪阶,然后把原來的數(shù)組拷貝過來昌抠,再將原數(shù)組釋放掉即可。

這一次沒有了STL的便利鲁僚,我又費(fèi)盡周折的用純C實(shí)現(xiàn)了一版評價(jià)算法炊苫,但是編譯執(zhí)行后竟然報(bào)了一個(gè)系統(tǒng)級的錯(cuò)誤。這另我百思不得其解冰沙,因?yàn)槲以诹硪粋€(gè)幾千節(jié)點(diǎn)規(guī)模的小型網(wǎng)絡(luò)中對程序進(jìn)行了測試侨艾,能夠得到正確結(jié)果,至少說明這一版程序在邏輯上是沒有問題的倦淀。在后續(xù)的調(diào)試過程中,我發(fā)現(xiàn)當(dāng)程序運(yùn)行到某一階段時(shí)声畏,錯(cuò)誤會(huì)出現(xiàn)在malloc申請內(nèi)存這一行(如果使用realloc同樣會(huì)有類似的情況)撞叽,而函數(shù)中的參數(shù)均正常。在我的理解中插龄,如果malloc申請內(nèi)存成功愿棋,則會(huì)返回對應(yīng)的指針,若申請內(nèi)存失敗均牢,則返回null糠雨,而現(xiàn)在的情況是直接報(bào)系統(tǒng)異常,確實(shí)讓我無法理解徘跪。

考慮到只有在網(wǎng)絡(luò)規(guī)模比較大時(shí)才會(huì)出現(xiàn)這種情況甘邀,我猜測這可能是與短時(shí)間內(nèi)高頻次、密集的申請釋放內(nèi)存有關(guān)垮庐,也許是底層哪里出了bug吧松邪。

經(jīng)歷了N次失敗,是時(shí)候進(jìn)行一下反思了哨查,我把目前所遇到的困難和限制進(jìn)行了梳理:

  • 內(nèi)存限制逗抑,這要求我們不能采用粗暴的內(nèi)存申請方式
  • 效率問題,這要求我們在能用C的情況下盡量用C(用C++的vector也得用指針?biāo)饕姆绞剑€不知直接用C)
  • 未知底層bug的困擾邮府,這要求我們盡量少在程序運(yùn)行過程中頻繁申請和釋放內(nèi)存

這看起來完全無解荧关!然而,巧合的時(shí)褂傀,在某天值班的時(shí)候忍啤,我突然想起了以前學(xué)漏洞利用時(shí),看了很長一段時(shí)間的Linux堆內(nèi)存管理的機(jī)制紊服,瞬間找到了突破口檀轨。

0x04 堆內(nèi)存管理的啟發(fā)

Linux的堆內(nèi)存管理可謂博大精深,過于復(fù)雜的理論和實(shí)現(xiàn)細(xì)節(jié)就不涉及了欺嗤,這里我們只要重點(diǎn)關(guān)注其中的fast bin即可参萄。首先需要解釋幾個(gè)概念,在堆內(nèi)存管理中煎饼,我們把內(nèi)存塊稱為chunk讹挎,已分配給用戶的稱為allocated chunk,空閑的稱為free chunk吆玖。所謂堆內(nèi)存管理筒溃,最基本同時(shí)也是最重要的工作就是實(shí)現(xiàn)高效的分配和回收chunk。內(nèi)存中大量free chunk該如何記錄和索引呢沾乘?這就需要用到bin了怜奖,bin是一種記錄free chunk的鏈表數(shù)據(jù)結(jié)構(gòu)。Linux系統(tǒng)針對不同大小的free chunk翅阵,將bin分為了4類:

  • fast bin
  • unsorted bin
  • small bin
  • large bin

那到底什么是fast bin歪玲?看下面這張示意圖

[圖片上傳失敗...(image-d89e3c-1514533769167)]

其中main_arena.fastbinsY對應(yīng)的就是fast bin,而fast bin下方用鏈表串起來的塊就是free chunk掷匠,為了和其他chunk區(qū)分開來滥崩,我們稱之為fast chunk。乍一看讹语,fast bin不就是個(gè)指針數(shù)組(鏈表)嗎钙皮?數(shù)組中每一個(gè)元素都是一個(gè)指針,分別指向不同大小的fast chunk鏈表的頭節(jié)點(diǎn)顽决。沒錯(cuò)短条,從本質(zhì)上看fast bin就是一個(gè)簡單的指針數(shù)組,但可別小看了fast bin才菠,它是所有bin中操作速度最快的慌烧,這與它的用途和巧妙設(shè)計(jì)是分不開的。我認(rèn)為fast bin的高效源于兩個(gè)方面:

  • 按大小管理fast chunk:從圖中可以看出鸠儿,每個(gè)fast bin所管理的fast chunk大小是不同的屹蚊,第一個(gè)為16 bytes厕氨,后面依次為32 bytes和64bytes,分別滿足不同大小的內(nèi)存申請需求汹粤,也避免了空間的浪費(fèi)命斧。

  • 分配與回收fast chunk采用了LIFO(后進(jìn)先出)算法:fast chunk雖然是用單鏈表連接起來的,但其操作方式卻更像棧嘱兼,因?yàn)樗胁僮鞫际窃阪湵砦策M(jìn)行的国葬。用戶釋放內(nèi)存(free)時(shí),空閑出來的fast chunk根據(jù)其大小添加到對應(yīng)的鏈表尾上芹壕;用戶申請內(nèi)存(malloc)時(shí)汇四,滿足要求的fast chunk從對應(yīng)的鏈表尾上卸下,分配給用戶使用踢涌。這是一個(gè)典型的LIFO(后入先出)算法通孽,這樣做有什么好處呢?大家以前學(xué)習(xí)操作系統(tǒng)的時(shí)候應(yīng)該知道內(nèi)存中的頁面調(diào)度算法有LRU和LFU等睁壁,無論哪種都是希望最近使用過的內(nèi)存頁盡量駐留在物理內(nèi)存中背苦,以減少缺頁中斷的觸發(fā)。而LIFO算法恰到好處的配合了這個(gè)特性潘明,用戶最近釋放的內(nèi)存(表明最近被使用過行剂,有很大可能直接就在物理內(nèi)存中)下一次就是最先被分配出去的,因此保證了fast bin在時(shí)間效率上也極高钳降。

0x05 評價(jià)算法的最終實(shí)現(xiàn)

前面花了大量篇幅講解堆內(nèi)存管理的原理厚宰,到底與我們的問題有什么關(guān)系呢?我們再回顧一下前面遇到的難題遂填,即要節(jié)約空間铲觉,又要減少運(yùn)行時(shí)頻繁的申請和釋放內(nèi)存,結(jié)合上一節(jié)說的堆內(nèi)存管理城菊,我們的問題似乎都可以依靠堆內(nèi)存管理來解決备燃。是不是可以自己模擬一個(gè)算法層面的堆內(nèi)存管理器呢碉克?姑且稱之為SHMM(Simulated Heap Memory Manager)好了凌唬。

試想一下,在程序開始階段漏麦,我們提前把所需要的內(nèi)存申請完畢客税,并按照其大小分門別類管理起來。在程序的運(yùn)行過程中撕贞,所有的內(nèi)存申請和釋放過程由SHMM“接管”更耻。申請內(nèi)存就不是使用malloc了,而是由SHMM從提前申請好的內(nèi)存中找出一個(gè)大小相匹配的空閑塊捏膨,交由程序使用秧均;釋放內(nèi)存也不再是free了食侮,而是由SHMM重新標(biāo)記為空閑塊并管理起來。

還有一個(gè)問題目胡,我們怎么知道一開始申請多少內(nèi)存夠呢锯七?這就涉及到合理的設(shè)計(jì)空閑塊的大小和數(shù)量了,回顧一下評價(jià)算法(以40萬節(jié)點(diǎn)為例)誉己,假設(shè)算法進(jìn)行到了最后一步眉尸,此時(shí)僅剩最后兩個(gè)集團(tuán),其中一個(gè)集團(tuán)規(guī)模為30萬巨双,另一個(gè)集團(tuán)規(guī)模為10萬噪猾,合并以后得到規(guī)模為40萬集團(tuán)。這個(gè)過程僅需要一個(gè)40萬大小的空閑塊(開始實(shí)際存30萬個(gè)節(jié)點(diǎn)筑累,合并后存40萬節(jié)點(diǎn))和10萬大小的空閑塊即可袱蜡。進(jìn)一步反推和擴(kuò)展,不難得出下面這個(gè)方案:

  • 40萬大小空閑塊*1≈1.5MB
  • 20萬大小空閑塊*2≈1.5MB
  • 10萬大小空閑塊*4≈1.5MB
  • ……
  • 98大小空閑塊*4096≈1.5MB
  • 49大小空閑塊*8192≈1.5MB
  • ……
  • 4大小空閑塊*131072≈1.9MB

可以看出疼阔,以上方案基本上可以滿足任意cluster添加節(jié)點(diǎn)或是合并的需求戒劫,且所需內(nèi)存空間不超過30MB!

那么具體該怎么實(shí)現(xiàn)婆廊?直接看我畫的示意圖:

[圖片上傳失敗...(image-86a615-1514533769167)]

由于是示意圖迅细,我只畫了三種大小的空閑塊,大家領(lǐng)會(huì)意思即可淘邻。clusters在這里是作為索引所有cluster(無論是空閑的還是已經(jīng)分配的cluster)的指針數(shù)組茵典,在程序的開始階段,就需要根據(jù)當(dāng)前網(wǎng)絡(luò)的規(guī)模宾舅,按上面的模式一次性申請完所有空閑塊內(nèi)存统阿。其中,每個(gè)cluster的結(jié)構(gòu)我也畫在了圖中筹我,一目了然扶平。

下面就是最重要的部分:模擬實(shí)現(xiàn)堆內(nèi)存管理。這里我模仿fast bin設(shè)計(jì)了一個(gè)freelist蔬蕊,如下圖所示

[圖片上傳失敗...(image-ccd72f-1514533769167)]

其原理不再贅述结澄,就是把fast bin照搬過來。不過需要指出的是岸夯,freelist中實(shí)際存儲(chǔ)的并非cluster或指向cluster的指針麻献,而是空閑的cluster在clusters上的索引〔掳纾基于freelist結(jié)構(gòu)勉吻,很容易實(shí)現(xiàn)cluster的“申請”、“釋放”與“合并”函數(shù)旅赢。

利用算法模擬出來的堆內(nèi)存管理齿桃,完美的避開了毫無頭緒的詭異bug惑惶,在所有代碼全部完成之后,再次編譯執(zhí)行短纵,成功集惋!更為重要的是,在時(shí)間效率上有了顯著提升踩娘,執(zhí)行速度吊打官方的groovy版本刮刑。

0x06 最后一公里&并行化提速

現(xiàn)在我們手里有了C語言版的評價(jià)算法,已經(jīng)邁過了最艱難的一道坎养渴,下面就是考慮如何完成的終極目標(biāo)了雷绢。

在上一篇文章中,我已經(jīng)把思路講的很詳細(xì)了:第一步先用帶貪心策略的PageRank算法得到一個(gè)初始序列理卑,第二部在評價(jià)算法的基礎(chǔ)上優(yōu)化這個(gè)序列翘紊。

在實(shí)現(xiàn)貪心策略的PageRank算法時(shí),我用到了igraph這個(gè)庫藐唠,實(shí)現(xiàn)起來也比較簡單帆疟,這里直接略過。在實(shí)現(xiàn)第二步的過程中宇立,需要注意和評價(jià)算法的區(qū)別:在評價(jià)算法中沒有搜索窗口踪宠,將節(jié)點(diǎn)添加到當(dāng)前網(wǎng)絡(luò)以及更新當(dāng)前網(wǎng)絡(luò)的最大集團(tuán)規(guī)模的操作是同步進(jìn)行的;而在有搜索窗口的情況下妈嘹,需要先尋找使當(dāng)前網(wǎng)絡(luò)最大集團(tuán)規(guī)模最小的節(jié)點(diǎn)柳琢,然后再執(zhí)行添加節(jié)點(diǎn)的操作。

至此润脸,我們后續(xù)的過程就是不斷調(diào)整$k$的取值刷結(jié)果了柬脸,$k$值在幾百到幾千的范圍內(nèi)時(shí),運(yùn)行速度非常塊毙驯。但是隨著$k$值的不斷增大倒堕,運(yùn)行速度急劇下降。如果打開系統(tǒng)性能監(jiān)視器可以看到爆价,在我們的多核的機(jī)器上垦巴,滿負(fù)荷運(yùn)行的只有一個(gè)核,這是對系統(tǒng)性能的極大浪費(fèi)允坚!想要進(jìn)一步提速必須將原來的程序并行化魂那,采用多線程的方式執(zhí)行蛾号,但是并非所有程序都能夠簡單的并行化稠项。以我們這個(gè)問題為例,添加節(jié)點(diǎn)的過程有著非常強(qiáng)的前后依賴性鲜结,只有在前一個(gè)節(jié)點(diǎn)加入到網(wǎng)絡(luò)之后展运,相關(guān)的集團(tuán)合并等更新操作完成之后才能夠添加下一個(gè)節(jié)點(diǎn)活逆。對于有前后依賴性的程序片段,我們是無法進(jìn)行并行化改造的拗胜。

但是蔗候,在搜索窗口中的尋找最優(yōu)節(jié)點(diǎn)的過程就沒有這個(gè)限制,如下圖所示

[圖片上傳失敗...(image-1d8752-1514533769167)]

我們前面說過埂软,尋找最優(yōu)節(jié)點(diǎn)的過程并不修改當(dāng)前網(wǎng)絡(luò)結(jié)構(gòu)锈遥,而是在找到最優(yōu)節(jié)點(diǎn)后再將其添加到網(wǎng)絡(luò)中。由于當(dāng)前網(wǎng)絡(luò)結(jié)構(gòu)不變勘畔,因此每一次尋找并計(jì)算的過程都是互相獨(dú)立的所灸,這就很適合并行化改造。當(dāng)然炫七,這里的并行化改造并不要求大家有豐富的并行編程經(jīng)驗(yàn)爬立,也不需要使用CUDA之類的牛刀。我們可用簡單方便的OpenMP庫万哪,只需要添加幾行編譯器指令就能夠輕松實(shí)現(xiàn)并行化侠驯。關(guān)于OpenMP的使用,大家可以參考網(wǎng)上的諸多教程奕巍。在具體的使用過程中吟策,要盡量避免數(shù)據(jù)依賴和競爭,設(shè)置好臨界區(qū)的止。

再次編譯執(zhí)行可以發(fā)現(xiàn)踊挠,此時(shí)所有的核都處于滿載運(yùn)行狀態(tài),運(yùn)行速度有了顯著提升冲杀。

0x07 實(shí)現(xiàn)代碼&小結(jié)

代碼已上傳到我的github效床,歡迎大家拍磚~

剩下的就是找最優(yōu)的$k$值了,這個(gè)過程就是手工嘗試了……依靠著諸多高效的改進(jìn)和堅(jiān)持不懈的努力权谁,我最終刷到了第四名剩檀。當(dāng)然還有繼續(xù)上升的空間,不過限于時(shí)間沒有做更多嘗試了旺芽。

[圖片上傳失敗...(image-25410f-1514533769167)]

仔細(xì)思考起來沪猴,在很多細(xì)節(jié)上還有可以進(jìn)一步優(yōu)化的地方,例如:

  • 設(shè)置一個(gè)搜索窗口起點(diǎn):在構(gòu)建網(wǎng)絡(luò)的初期采章,幾乎所有節(jié)點(diǎn)的度都是1运嗜,都是自成一個(gè)集團(tuán),這個(gè)時(shí)候是沒有必要在搜索窗口中找最優(yōu)點(diǎn)的悯舟。
  • 搜索過程的提前終止:當(dāng)搜索窗口找到一個(gè)節(jié)點(diǎn)担租,使當(dāng)前集團(tuán)規(guī)模無變化時(shí)(加入了其他小集團(tuán)),可以提前結(jié)束搜索過程抵怎。

以上可以在真正的實(shí)踐中慢慢優(yōu)化了奋救。

從工程化實(shí)現(xiàn)的過程來看岭参,我們經(jīng)歷了一段非常崎嶇的路程,事實(shí)上任何大型項(xiàng)目的實(shí)現(xiàn)過程都無法避開高效尝艘、可拓展等坑演侯,這也是一段必由之路。

那么如果你對我的參賽感悟和一些其他閑扯感興趣的話背亥,歡迎關(guān)注本系列的第三篇文章~

如果你覺得本文對你有幫助秒际,歡迎打賞我一杯咖啡錢~

[圖片上傳失敗...(image-21964a-1514533769167)]

參考資料

C++的效率相關(guān)

Linux堆內(nèi)存管理相關(guān)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市狡汉,隨后出現(xiàn)的幾起案子程癌,更是在濱河造成了極大的恐慌,老刑警劉巖轴猎,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嵌莉,死亡現(xiàn)場離奇詭異,居然都是意外死亡捻脖,警方通過查閱死者的電腦和手機(jī)锐峭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來可婶,“玉大人沿癞,你說我怎么就攤上這事∶剩” “怎么了椎扬?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長具温。 經(jīng)常有香客問我蚕涤,道長,這世上最難降的妖魔是什么铣猩? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任揖铜,我火速辦了婚禮,結(jié)果婚禮上达皿,老公的妹妹穿的比我還像新娘天吓。我一直安慰自己,他們只是感情好峦椰,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布龄寞。 她就那樣靜靜地躺著,像睡著了一般汤功。 火紅的嫁衣襯著肌膚如雪物邑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天,我揣著相機(jī)與錄音拂封,去河邊找鬼。 笑死鹦蠕,一個(gè)胖子當(dāng)著我的面吹牛冒签,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钟病,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼萧恕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肠阱?” 一聲冷哼從身側(cè)響起票唆,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屹徘,沒想到半個(gè)月后走趋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡噪伊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年簿煌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鉴吹。...
    茶點(diǎn)故事閱讀 40,918評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡姨伟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出豆励,到底是詐尸還是另有隱情夺荒,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布良蒸,位于F島的核電站技扼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嫩痰。R本人自食惡果不足惜淮摔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望始赎。 院中可真熱鬧和橙,春花似錦、人聲如沸造垛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽五辽。三九已至办斑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乡翅。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工鳞疲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蠕蚜。 一個(gè)月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓尚洽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親靶累。 傳聞我的和親對象是個(gè)殘疾皇子腺毫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評論 2 361

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