某一日,從雲風的SkyNet群(QQ群)裡知道 DouBan(豆瓣) 上有人噴雲風,是從 ”《怎樣識別水貨程序員》說的是真的嗎?” 這個《知乎》帖子開始的,
當初也是看了個大概,實在對知乎、豆瓣之類的不太感冒,文字又長,瞄了一下完事。其實我一開始沒弄清是在豆瓣還是知乎上噴他,今天才看明白經過。
知乎上提到的兩個(豆瓣)原帖分別是:《怎樣識別水貨程序員》和 《怎樣識別正品程序員》,這兩個原帖我好像看過第一個,今天才認真看了看,
原來討論還挺多的……想了解來龍去脈的可以去看看。
下面是《知乎》上的帖子截圖:
一開始噴公認的水貨,XX,還有有爭議的陳皓(注意是陳皓,不是陳碩!尼瑪的我都弄錯了);然後是比較隱藏的水貨,陳碩(樓主:陳碩有些文章還是不錯的,某些文章的確是大自然的搬運工,搬得差了一點,不過好歹也搬了,也比不搬的搬運工要好一點,多少給人一些啟示);然後就是最隱蔽的雲風了,他說的的確也有些道理,雲風在我看來,近些年寫的東西你說不痛嘛,也有點氧,你說有點氧嘛卻又撓得不舒服,只是當消遣來看看,偶爾關注下。不過多少還是有些實力,只不過雲風太飄逸,也略微顯得有些虛。
無論是陳碩還是雲風,作為開發者,我多少還是有幾分敬仰的(我改寫folly的string類的時候,還搜到了不少陳碩寫的東西,多多少少還是給了我些幫助),噴人者 Sinclair 多少還是有些偏激,不過有些話也有些道理,所以也不太能反駁,反正我們就看看熱鬧呗。
看了下回復,閒得蛋疼的人還真多,就算我是個不上班,作息隨意的人都沒有這個閒工夫來閒扯這些,不是今天要寫這個東西,我都懶得看。
然後是灌水第二貼,開始噴雲風了,這才露出真面目。開始討論的雲風的悲觀鎖,樂觀鎖,還說雲風把cas改成spinlock,整個過程,倒是符合雲風的做風,雖然我並不清楚事情的來龍去脈。然後此人開始賣弄自己的英文和專業術語,可憐我的英文四級都沒過,有個把單詞不查字典咱還不認識,好高端。。。真是有點無語,有本身通篇英文嘛,咱也還是能看懂的。他提到的雲風的問題我也沒法反駁,好在我對緩存的認識也是頗深的,具體可以看我的項目(https://github.com/shines77/fast_matmult 裡面的 matmult_s_row_tiling_K_sse2_2x4_packed.cpp ,看我是怎麼把L1, L2 Cache一點一點搾干的,當然這個比GotoBLAS2最快的方法還是差那麼一點點,不過這個方法是我自己發現的(其實也不能叫發現,只能叫實現),GotoBLAS2的那個思路的確比較難想到,我的項目裡也有他的方法的實現,在 gemm_kernel_2x4_penryn.cpp 裡)。對於緩存和CPU的一些描述,對錯都不重要,但是你秀這麼多英文就是你的不對了哦。(看帖子裡他說他聽同學說 pastebin.com 被牆了,莫非這位老兄不在國內,怪不得E文用得這麼多,原來是海龜啊)
我長話短說吧,不然你會看不下去了,於是此人開始貼代碼啦。來證明他不是“水貨程序員”,是真正的“並發專家”。知乎上那個帖子原來是評論 Sinclair 的各個版本的代碼的,看著有點令人糊塗,update1, update2, update3,我還以為是 Sinclair 自己寫的說明。其實我是有 Sinclair 那個貼代碼的帖子的,也有他的代碼。好了,不羅嗦,上他的貼代碼的帖子吧:《實打實的代碼,實打實的性能分析》
這個帖子你是必須要看的,因為這就是本文標題提到的“血案”正文,當初我也沒看完,我大概看到q3.h, qlock.h就沒往下看了(或者還有一個原因是有些部分可能也是他後來才更新的),就往後面看兩人的正面交鋒了。就在寫這篇文章的前幾天,秉著負責的態度,我重新看了一遍這個帖子的正文,才發現,其實後面還更新了a2.c, a3.c,我後來做的一些工作他也做了,比如合理性驗證,不過我覺得我做得更好一點,你看我的代碼便知。我把各個線程pop出來的消息保存到各個線程的局部list裡面,這樣線程之間記錄list的時候並不需要原子操作,而且區分各個線程的id編號是極容易的事情。關於合理性的驗證,除了和他一樣的檢測flag的唯一性以外,我還想了一個更進一步的驗證方式,詳細可以看我在RingQueue_Test()裡注釋掉的一些代碼。不過想想,檢測flag的唯一性(其實我的代碼裡是叫編號唯一性,我給每個消息編了個號,從1~MSG_TOTAL_LENGTH)已經基本上滿足合理性要求了,也就算了,因為那個方法理解上雖不難,但代碼實現起來卻比較麻煩。
下面開始上代碼:
在《實打實的代碼,實打實的性能分析》一文裡,提到了3個版本,一個是qlock.h(朱欣愚的版本),一個是q.h(雲風的版本),一個q3.h(Sinclair 的版本),還有測試代碼 a.c,當初我是拿到這四個文件就開始測試了(一開始我也只是看看而已,並沒有編譯和Run,我也不記得什麼時候開始弄的)。由於 Sinclair 的帖子貼的地址是 pastebin.com 的,需要翻~牆才能看到,所以我把他們都上傳到github了,地址如下:
https://github.com/shines77/RingQueue/blob/master/douban/q.h
https://github.com/shines77/RingQueue/blob/master/douban/q3.h
https://github.com/shines77/RingQueue/blob/master/douban/qlock.h
https://github.com/shines77/RingQueue/blob/master/douban/a.c
https://github.com/shines77/RingQueue/blob/master/douban/a2.c
https://github.com/shines77/RingQueue/blob/master/douban/a3.c
https://github.com/shines77/RingQueue/blob/master/douban/mq.c
如果寫到這裡,你還不知道雲風是誰,那麼科普一下,雲風,本名吳雲洋,知名游戲開發者,網名CloudWu,他的博客:http://blog.codingnow.com/,曾經是網易技術骨干,後來在杭州創辦網易杭州分公司,負責研發。1999年初開始制作二維游戲引擎--風魂系列,被多家公司和小組用於游戲制作。百度百科:http://baike.baidu.com/view/2750617.htm(網易雲風),雲風的GitHub:https://github.com/cloudwu,201x年離開網易,合伙創辦廣州簡悅,著有開源服務器框架SkyNet,開源2D游戲引擎ejoy2d等,已上線的游戲比較火的有《陌陌爭霸》、《狂刃》(代理)、《天天來戰》等。
我們可以看到,在《實打實的代碼,實打實的性能分析》裡,雲風第一個回復就應戰了,時間是13日早上10點多,
由於某些原因,我是第三天(即15日)下午3、4點左右才知道的(我特意查閱了Q群聊天記錄求證的),大概那幾天我在忙
jemalloc的Windows版(Visual Studio版),大概中午過一點我才會起來並上網。
而後雲風提到這個是skynet的某個歷史版本,有個隱晦的bug,因為後來改了就沒有修復,再後面這句話是比較值得玩味的:
這就是大師的做事風范。。。而 Sinclair 這一番回復也引起了 SkyNet 群的一陣唏噓:
雙方都是大神啊,我等小民,屌絲自然是看不太明白。。。300M等於多少?我告訴你,3億!!!什麼東西有這麼多用戶?
你沒看錯,是一台機器!!並發請求300K = 30萬。
大師又發話了,尤其請注意最後畫紅線的地方(這絕不是空穴來風,晚一點我會給你SkyNet群裡更詳細的聊天截圖,
幾乎幾天就會重復一次,大師警言,必須聽好啊):
然後是兩人的互相扯皮,直到雲風這個回復,倒是開始有點進入狀態了,我也是看到這裡才找到點感覺,看代碼看評論,有點應接不暇:
不過雲風這個言論就。。呵呵了。。。
我很白目的發了言,這說明我大概下午3點多上的,後來還prompt(推廣)了一下jemalloc-win32的項目,有夠白目的。。。:
然後包括雲風在內的群裡部分人都在討論這個問題,我自然也不會放過啊,不管怎麼說都得關心下嘛,
我覺得這種討論,不管怎麼樣,只要結論是正確的或方向正確的,都是有益的。哪怕是很小的問題。
看到這樣的言論,我也是不好說什麼,你能理解我為什麼要寫這個東西了吧,這還是前菜,還有很多。
雲風說的我也基本認可,但是也不認可,看來這次他倒是道出了一些實話,但這遠遠還不夠,雖然我知道你知道,
但是的確,由於每個人處於的階段或工作不同,你不能這麼武斷的下一個結論,至於是什麼結論,你後面會看到很多的。
SkyNet群裡潛藏著一些腦殘粉,雖然我也不好說有多少,但是的確有,不是??至於為什麼有腦殘粉,我也不多說了。
只能說雲風太飄逸了,大俠後面沒有幾個跟班的,這不符合武俠小說的路數。
請注意下面截圖中的最後一句話,當然其他話也很重要:
當你讀完整篇文章以後,你將知道我為什麼把這一句劃起來。。。
好了,還是回歸正題,前面說到雲風 2014-12-15 14:07:20 回的那個帖子,多少回歸了一點理性,有些實際的根據(至少有實際的模擬),漫天空談沒有意義。
我也是在這個時候邊看 Sinclair 的代碼,邊看兩人的交鋒。我也對 Sinclair 的邊界判斷表示疑問,通過仔細分析以後,才知道其實 Sinclair 這個寫法,隊列的實際長度只有(QSzie - 1)個元素,原因大致跟雲風那個回復說的有點沾邊,我想這絕不是 Sinclair 的設計初衷,不過他也利於了unsigned int的一些特性,雖有缺陷,但寫法也是有點技巧的,但是通過仔細分析,我們可以找到更合理同時也准確的寫法。有問題的是這一句:
if ((mask + tail - head) < 1U) return -1;
慢著,不好意思,插播一下,看到這樣的言論,你說我們有不噴他的理由嗎?
對於第二點,你真的用多核解決了性能問題嗎?我怕是增加了哦!對於第三點,這個技巧在 Sinclair 的代碼是廣泛用到的,我也非常同意,雲風其實不懂Cache,但看他以前的blog,倒是應該知道的,這裡原因不明,可能他考慮不夠細致吧。這個以空間換效率的事情還是非常值得做的,非常非常值得!!
剛才看QQ群聊天記錄才發現,雲風公司的同事 8樓有點高(曾經看過他用go語言寫的好像goevent之類的,看來也不是等閒之輩) 寫了個測試,只看到push和pop的完成數量,以及測試完成的時間,由於看不到代碼,不好評價,我只是想說,這玩意不是很有概念,是很難寫正確的。而 Sinclair 的 q3.h 我後來的驗證也表示是正確的,不過有一段時間我的測試結果以為 q3.h 是錯誤的(原因是運行很久都不能完成,後來得知 q3.h 的使用是有條件限制的,結果雖是正確的,但有可能會LiveLock(活鎖),我以後會說到,你也可以從我的代碼裡得到這個結論。還有一個問題就是,其未出現bug不代表就一定是正確,因為我後來仔細分析過後,至少他的邏輯跟我最終設計的邏輯有些差別,的確是可能測試未能觸及極端的情況,沒能表現出來,但我後來放棄了他這樣的思路,因為這個思路再怎樣設計都不夠高效。)
8樓有點高 提到的這篇文章後來我也看了(陳碩寫的,看得出來是大自然的搬運工,不過搬得還行,http://coolshell.cn/articles/8239.html),這也給我們認清這個問題提供了一個更清晰的思路。而老鄧提到的兩個親和是不對的,但是padding和緩存讀寫沖突是對的,likely這種都不是事啦,不重要。看來老鄧的總結能力還是很強的。親和指的是CPU親和,即讓線程或進程只運行在指定的一個或幾個CPU核心上。後來他也提到了自己要用C++寫一個FixedQueue,倒也勾起了我後來寫RingQueue的想法。老鄧還真是一個牛比的人(我是真心的,每個人都有自己的特點和特長),我某些靈感都是從他那裡來的。。。
(前面我打住那部分明天再講……)
好了,其實前半部分的內容兩天前就已經就寫好了,我一直不知道怎麼繼續寫下去,現在我想好了,今天亂七八糟了補了一些,希望不要太介意。今天就先談到這裡,給你們一點時間去看代碼,去研究,看你能不能超過雲風,超過 Sinclair 。我寫的 RingQueue 的GitHub地址是:https://github.com/shines77/RingQueue,如果是不支持GBK編碼的編輯器或系統,可以下載UTF-8編碼版:https://github.com/shines77/RingQueue-utf8。還是很不錯的,我敢說是很棒的混合自旋鎖,後面你就會看到是為什麼。你現在也可以自己去下載回來看看,支持Makefile,支持CodeBlocks,支持Visual Studio 2008, 2010, 2013等,還支持CMake,支持Windows, MinGW, cygwin, Linux, Mac OSX等等,當然可能不支持ARM,沒測試環境。明天還有更加精彩的,敬請期待……未完待續……
(注:RingQueue依然是一個研究與測試的程序,請不要上綱上線,不過你有好的建議,可以告訴我,目前有一個東西一直沒弄進去,就是CPU是單核的時候是要判斷一下的,直接跳過Spin(自旋)。)