redis是單線程弄兜。
單線程還快的原因是:所有的數(shù)據(jù)都是在內(nèi)存中棋蚌,運(yùn)算都是內(nèi)存級(jí)別的。對(duì)于o(n)的指令要慎用挨队,不然會(huì)造成卡頓
單線程處理并發(fā):多路復(fù)用,非阻塞IO
非阻塞IO
當(dāng)使用套接字讀取的時(shí)候蒿往,默認(rèn)是阻塞的盛垦,read方法需要傳一個(gè)參數(shù)n,表示讀取這么多的字節(jié)后返回瓤漏,如果沒(méi)有讀取到這么多字節(jié)線程就會(huì)卡在那里腾夯,等新的數(shù)據(jù)過(guò)來(lái)颊埃,或者連接關(guān)閉,才會(huì)將數(shù)據(jù)返回蝶俱。write方法一般是不會(huì)阻塞的班利,除非內(nèi)核中為套接字分配的緩沖區(qū)已經(jīng)滿了,write方法就會(huì)阻塞榨呆,直到到緩沖區(qū)重新分配新的空間后罗标。
非阻塞IO,是在套接字對(duì)象加入一個(gè)Non_Blocking积蜻。當(dāng)這個(gè)選項(xiàng)打開的時(shí)候闯割,讀寫方法不會(huì)阻塞,而是能讀多少讀多少竿拆,能寫多少寫多少宙拉。讀寫多少取決于為內(nèi)核為套接字分配的讀寫緩沖區(qū)內(nèi)部的字節(jié)數(shù)。讀寫方法返回值會(huì)告知讀寫了多少字節(jié)丙笋。
事件輪詢(多路復(fù)用)
飛阻塞IO有一個(gè)問(wèn)題谢澈,就是結(jié)果讀寫到一半的時(shí)候就返回了,線程如何知道什么時(shí)候需要繼續(xù)讀咧御板?就是當(dāng)數(shù)據(jù)來(lái)的時(shí)候锥忿,線程是如何知道呢?寫的時(shí)候稳吮,怎么知道緩沖區(qū)滿了缎谷,寫不完了,剩下的數(shù)據(jù)該什么時(shí)候才能寫呢灶似?
事件輪詢API就是解決這個(gè)問(wèn)題的列林。
最簡(jiǎn)單的事件輪詢API就是select函數(shù),是操作系統(tǒng)提供的酪惭。輸入是讀寫描述符列表read_fds&write_fds希痴。輸出就是對(duì)應(yīng)的可讀可寫的事件,同時(shí)提供了timeout參數(shù)春感,當(dāng) 沒(méi)有任何事件到來(lái)砌创,會(huì)等timeout時(shí)間,線程處于阻塞狀態(tài)鲫懒。一旦期間有任何事件過(guò)來(lái)嫩实,就會(huì)立即返回。拿到事件后窥岩,線程順序處理相應(yīng)的事件甲献,處理完后過(guò)來(lái)輪詢,于是線程進(jìn)入了一個(gè)死循環(huán)颂翼,稱之為事件循環(huán)晃洒,一個(gè)循環(huán)一個(gè)周期
因?yàn)橥ㄟ^(guò)select函數(shù)調(diào)用處理多個(gè)管道描述符 的讀寫事件慨灭,所以稱之為多路復(fù)用API。現(xiàn)在操作系統(tǒng)多路復(fù)用已經(jīng)不用select函數(shù)了球及,而是使用epoll (linux) 氧骤,kqueue(freebsd & macosx),因?yàn)閟elect描述符多的時(shí)候性能變差吃引。他們的本質(zhì)都是差不多的筹陵。
事件輪詢API就是java中的NIO技術(shù)。
指令隊(duì)列
redis為每個(gè)客戶端套接字都關(guān)聯(lián)了一個(gè)指令隊(duì)列际歼,客戶端的指令通過(guò)隊(duì)列進(jìn)行順序處理惶翻,先到先處理。
響應(yīng)隊(duì)列
redis為每個(gè)客戶端套接字也提供了一個(gè)響應(yīng)隊(duì)列鹅心,服務(wù)器通過(guò)響應(yīng)隊(duì)列將響應(yīng)的結(jié)果返回給客戶端吕粗。如果隊(duì)列為空,意味著現(xiàn)在連接處于空閑狀態(tài)旭愧,不需要獲取事件颅筋,就是將客戶端描述符從write_fds中移除。當(dāng)隊(duì)列有數(shù)據(jù)的時(shí)候输枯,再將描述符添加到write_fds中议泵。應(yīng)避免selelct系統(tǒng)調(diào)用立即返回寫事件,這樣會(huì)使cpu瞬間升高桃熄。
定時(shí)任務(wù)
服務(wù)器在處理IO的時(shí)候還要處理其他的事情先口,如果線程阻塞在select上面,還是需要處理別的事情瞳收。
redis的處理方式是:
將定時(shí)任務(wù)記錄到稱之為最小堆的數(shù)據(jù)結(jié)構(gòu)中碉京,這個(gè)堆中,最快處理的任務(wù)排在堆的最上方螟深, 每個(gè)循環(huán)周期會(huì)處理排在最上面的任務(wù)谐宙,處理完之后, 將下一個(gè)最快執(zhí)行的任務(wù)還需要的時(shí)間記錄下來(lái)界弧,這個(gè)時(shí)間就是selelct系統(tǒng)調(diào)用的timeout的時(shí)間凡蜻,因?yàn)橹涝趖imeout時(shí)間內(nèi)沒(méi)有需要處理的任務(wù),所以可以安心的睡眠垢箕。