今天面試慘敗,面試官問了不到10個問題就讓我出來寫題了……對其中的一個題目印象深入:c++
Redis獲取字符串長度的複雜度是多少?
剛開始我是一臉懵逼的,由於不清楚Redis
的字符串類型是怎麼實現的,因此徹底無法答下去了……回來後立刻開始學習。面試
字符串是Redis
裏很是常見的類型,而用C
實現的Redis
和Java
不同。在C
裏字符串是用長度爲N+1
的字符數組實現的,且使用空字符串'\0'
做爲結束符號。獲取字符串的長度須要遍歷一遍,找到空字符串'\0'
才知道字符串的長度,複雜度是O(N)
。數據庫
若是有一個長度很是大的字符串,單線程的Redis
獲取它的長度就可能會阻塞好久,這是不能接受的,因此Redis
須要一種更高效的字符串類型。數組
Redis
實現了一個叫SDS(simple dynamic string)
的字符串類型,其中有兩個變量來分別表明字符串的長度和字符數組未使用的字符數量,這樣就能夠用O(1)
的複雜度來獲取字符串的長度了,並且一樣也是使用空字符串'\0'
做爲結束符號。學習
struct sdshdr { // 字符串長度 int len; // 字符數組未使用的字符數量 int free; // 保存字符串的字符數組 char buf[]; }
如今已經能夠回答上面的面試題了,實際上是很是簡單的一個問題,怪不得答不出來面試官立刻就說面試結束了……優化
SDS
在字符數組空間不足於容納新字符串的時候會自動擴容。ui
若是把一個C
字符串拼接到一個SDS
後面,當字符數組空間不足時,SDS
會先擴容到恰好能夠容納新字符串的長度,而後再擴充新字符串的空字符長度,最終SDS
的字符數組長度等於 2 * 新字符串 + 1(結束符號'\0')
。不過當新字符串的大小超過1MB
後,擴充的空字符長度大小會固定爲1MB
。spa
之因此會有這個機制,是由於Redis
做爲一個NoSQL
數據庫,會頻繁的修改字符串,擴容機制至關於給SDS
作了一個緩衝池。把SDS
連續增加N
次字符串須要內存重分配N
次優化成了SDS
連續增加N
次字符串最多須要內存重分配N
次,這其實和Java
裏的StringBuilder
實現思想是同樣的。線程
此次翻車是有緣由的,我看過兩本關於Redis
的書,裏面都是講Redis
如何實戰的可是並無講Redis
的設計和實現。這也就致使了面試很尷尬,由於面試官最喜歡問原理相關的東西了,因此之後學習技術的時候不要從實戰類的書籍開始了,仍是先看懂原理比較好。設計
這是《Redis設計與實現》
裏字符串一節的總結。