這篇文章將為大家詳細(xì)講解有關(guān)redis中線程IO模型是什么,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
創(chuàng)新互聯(lián)為客戶提供專業(yè)的成都做網(wǎng)站、成都網(wǎng)站建設(shè)、程序、域名、空間一條龍服務(wù),提供基于WEB的系統(tǒng)開發(fā). 服務(wù)項目涵蓋了網(wǎng)頁設(shè)計、網(wǎng)站程序開發(fā)、WEB系統(tǒng)開發(fā)、微信二次開發(fā)、手機網(wǎng)站制作等網(wǎng)站方面業(yè)務(wù)。
Redis是一個單線程的應(yīng)用程序,NodeJs、Nginx都是單線程,它們都屬于服務(wù)器高性能的典范。
Redis之所以是單線程還能這么快的原因:
其一是因為它所有的數(shù)據(jù)都在內(nèi)存當(dāng)中,所有的運算都是內(nèi)存級別的運算,所以使用redis時,要注意時間復(fù)雜度為O(n)的指令,因為是單線程的,如果數(shù)據(jù)量太大,會讓其他指令被阻塞等待;
其二是因為redis使用非阻塞IO與多路復(fù)用處理大量的客戶端連接。
當(dāng)我們使用套接字的讀寫方法時,默認(rèn)是阻塞的,
即調(diào)用read方法傳遞一個參數(shù)n,表示最多讀取n個字節(jié)后返回,如果一個字節(jié)都沒有,線程就會在read方法這里持續(xù)等待,直到有數(shù)據(jù)過來或者連接被關(guān)閉,read方法此時返回,線程才能執(zhí)行下面的邏輯,
write方法一般不會阻塞,除非內(nèi)核為套接字分配的寫緩沖區(qū)滿了,write方法才會阻塞,一直到緩存區(qū)中有空間閑出來。
下圖是套接字讀寫的細(xì)節(jié)流程。
非阻塞IO在使用套接字時提供了一個選項Non_Blocking,當(dāng)這個選項打開時,讀寫方法不會阻塞,而是能讀多少讀多少,能寫多少寫多少,
能讀多少取決與內(nèi)核為套接字分配的讀緩沖區(qū)的數(shù)據(jù)字節(jié)數(shù),能寫多少取決于內(nèi)核為套接字寫緩沖區(qū)分配的數(shù)據(jù)字節(jié)數(shù),
讀寫方法都會通過返回值告訴程序讀寫了多少字節(jié)數(shù)。
非阻塞IO意味著讀寫時,線程不必再被阻塞著,讀寫可以瞬間完成,線程可以繼續(xù)往下做別的事情。
非阻塞IO雖然很快,但是也帶來一個問題,線程讀數(shù)據(jù),讀了一部分就返回了,沒有讀完,剩下的數(shù)據(jù)何時繼續(xù)讀?,寫數(shù)據(jù),緩沖區(qū)滿了,沒有寫完,剩下的數(shù)據(jù)何時繼續(xù)寫?
當(dāng)可以繼續(xù)讀或者可以繼續(xù)寫時,應(yīng)該給應(yīng)用程序一個通知,告訴應(yīng)用程序可以繼續(xù)讀或者繼續(xù)寫,事件輪詢API就是用來處理這個問題的。
select
操作系統(tǒng)提供了一個select函數(shù)給用戶程序,輸入是讀寫描述符列表 read_fds & write_fds,輸出是與之對應(yīng)的可讀可寫事件,
同時還提供了timeout參數(shù),線程最多等待timeout的時間,在這期間有事件過來,方法立刻返回,線程往下處理,如果超過timeout時間,方法也會返回,
如果拿到事件了,線程即可挨個處理相應(yīng)的事件,處理完了以后繼續(xù)調(diào)用 select api 輪詢,所以該線程其實是一個死循環(huán),不停的 select,不停的處理,來回這樣,這個死循環(huán)被稱之為事件循環(huán),一個循環(huán)即一個周期。
事件循環(huán)偽代碼:
while True read_events, write_events = select(read_fds, write_fds, timeout) for event in read_events: handle_read(event.fd) for event in write_events: handle_write(event.fd) handle_others() # 做其他的邏輯處理,處理定時任務(wù)等等
通過select函數(shù)我們可以處理多個通道描述符的讀寫事件,所以將select這類的系統(tǒng)函數(shù)調(diào)用稱之為多路復(fù)用API,
現(xiàn)代操作系統(tǒng)的多路復(fù)用API已經(jīng)不使用select系統(tǒng)調(diào)用,改用epoll(linux)和kqueue(FreeBSD、macosx),
select的性能在描述符變多時會變得很差,epoll與select使用起來略有差異,不過都可以用上面的偽代碼理解,都是當(dāng)描述符發(fā)生事件時,循環(huán)對描述符的事件做出處理,
serversocket對象的讀操作是指調(diào)用accept接受客戶端新連接,何時有連接來臨,也是通過select調(diào)用的讀事件通知的。
Java中的NIO技術(shù)就是事件輪詢,其他語言也有這個技術(shù)。
Redis為每一個客戶端套接字關(guān)聯(lián)一個指令隊列,客戶端發(fā)來的指令通過隊列進行先進先出的順序處理。
同樣Redis返回的結(jié)果也通過為每個客戶端關(guān)聯(lián)的一個隊列返回,如果隊列為空,則暫時不需要去獲取寫事件,
此時會將該客戶端描述符從write_fds里移除,等隊列有數(shù)據(jù)的時候,再將描述符放進去,這樣可以避免select系統(tǒng)調(diào)用返回寫事件時,發(fā)現(xiàn)沒數(shù)據(jù)可寫,造成空輪詢、無用輪詢,對機器CPU的消耗。
服務(wù)器不單要響應(yīng)IO事件,有些其他的事情也需要處理,例如應(yīng)用程序自身的定時任務(wù),如果線程阻塞在select調(diào)用上,等待select的返回,這會造成有些定時任務(wù)到期了,卻沒有執(zhí)行,
Redis的定時任務(wù)記錄在一個稱為 最小堆 的數(shù)據(jù)結(jié)構(gòu)中,這個堆中,最快要執(zhí)行的任務(wù)排在最上方,每個循環(huán)周期里,redis會對堆中已經(jīng)到時間點的任務(wù)進行處理,
處理完畢后,將堆中即將要執(zhí)行的任務(wù)還需要的時間記錄下來,再次調(diào)用select時,這個時間就是timeout的值,在這期間內(nèi)不會有其他任務(wù)需要執(zhí)行了,redis可以放心的最多阻塞這么久,然后到時間后進行相應(yīng)的處理。
NodeJs和Nginx的事件處理原理和Redis也是類似的形式。
關(guān)于“Redis中線程IO模型是什么”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
標(biāo)題名稱:Redis中線程IO模型是什么
網(wǎng)站URL:http://www.chinadenli.net/article22/iejgcc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗、全網(wǎng)營銷推廣、網(wǎng)站制作、建站公司、App開發(fā)、網(wǎng)站設(shè)計公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)