欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解redis數(shù)據(jù)結(jié)構(gòu)之sds

 更新時間:2017年05月14日 17:05:23   作者:愛寶貝丶  
sds是Simple Dynamic String的縮寫,譯為簡單動態(tài)字符串,redis使用該結(jié)構(gòu)保存字符串,不同于c中的字符串,redis使用該結(jié)構(gòu)來更方便的進行字符串的處理,需要的朋友可以參考下

詳解redis數(shù)據(jù)結(jié)構(gòu)之sds

  字符串在redis中使用非常廣泛,在redis中,所有的數(shù)據(jù)都保存在字典(Map)中,而字典的鍵就是字符串類型,并且對于很大一部分字典值數(shù)據(jù)也是又字符串組成的。以下是sds的具體存儲結(jié)構(gòu):

      從圖中可以看出,sds的屬性有三個:len、free和buf數(shù)組。這里len字段是用來保存sds字符串中所包含字符數(shù)目的,free字段則是用來保存buf數(shù)組中空余的部分的長度的,而buf數(shù)組則是實際用來保存字符串的。比如如下結(jié)構(gòu)保存了“Hello World!”這個字符串:

      這里需要注意的是,sds和c字符串一樣,需要在字符串結(jié)尾加上一個“\0”表示該字符串的結(jié)束。這里這個sds對象的len屬性保存了“Hello World!”這個字符串的長度,而free屬性保存了數(shù)組中空余的位數(shù),buf數(shù)組則實際保存了這個字符串,空字符和空余位。

      redis使用sds結(jié)構(gòu)而不用c字符串保存字符串的原因有如下幾點:

      ①常數(shù)復(fù)雜度獲取字符串長度

      通過讀取sds對象的len屬性的值我們可以使用O(1)獲取sds對象保存的字符串長度,而在c字符串中,我們必須對整個數(shù)組進行遍歷從而獲取字符串的長度,其時間復(fù)雜度為O(N)。

      ②杜絕緩沖區(qū)溢出

      在c字符串中,比如char *strcat(char *dest, const char *src)函數(shù)將src連接到dest的末尾,但是c字符串假定dest數(shù)組中有足夠的空余空間來保存src數(shù)組,如果dest數(shù)組長度不夠就會造成緩沖區(qū)溢出;在sds對象中也提供了類似的函數(shù)sds sdscat(sds s, const char *t)和sds sdscatsds(sds s, const sds t),這兩個函數(shù)在調(diào)用之前會檢查目標(biāo)sds對象s中free屬性是否能夠保存要連接的字符串的長度,如果不夠,就會對目標(biāo)sds對象擴容,這就保證了sds對象不會造成緩沖區(qū)溢出。

      ③減少修改字符串時內(nèi)存重分配的次數(shù)

      在對sds進行修改的時候,redis可以通過“空間預(yù)分配”和“惰性空間釋放”來保證后續(xù)對sds對象的頻繁修改而不會造成sds對象的buf數(shù)組經(jīng)常分配空間;而對于c字符串,每次對其進行修改都需要進行一次空間分配和復(fù)制操作。

      ④二進制安全

      對于c字符串,由于其判斷是否結(jié)束的標(biāo)志是從字符串開始到結(jié)尾碰到的第一個“\0”字符,這就限制了c字符串不能保存像圖片、音頻、視頻、壓縮文件等二進制保存的內(nèi)容;而對于sds對象,由于判斷其是否結(jié)束的標(biāo)志是其len屬性,也就是說無論在len長度內(nèi),buf數(shù)組中是否包含“\0”都不影響redis判斷其是否結(jié)束。

      上面講到了sds的空間預(yù)分配和惰性空間釋放,sds通過這兩種操作極大的簡化了其對字符串的修改和對空間的分配工作。

      空間預(yù)分配指的是當(dāng)對一個sds對象進行結(jié)構(gòu)性增加時,比如修改其內(nèi)容使其增長或者連接另一個字符串到其末尾,sds會預(yù)先分配一定的空間以預(yù)防未來可能對其進行的修改。如下是redis進行空間預(yù)分配的主要代碼:

sds sdsMakeRoomFor(sds s, size_t addlen) {

  struct sdshdr *sh, *newsh;

  // 獲取 s 目前的空余空間長度
  size_t free = sdsavail(s);

  size_t len, newlen;

  // s 目前的空余空間已經(jīng)足夠,無須再進行擴展,直接返回
  if (free >= addlen) return s;

  // 獲取 s 目前已占用空間的長度
  len = sdslen(s);
  sh = (void*) (s-(sizeof(struct sdshdr)));

  // s 最少需要的長度
  newlen = (len+addlen);

  // 根據(jù)新長度,為 s 分配新空間所需的大小
  if (newlen < SDS_MAX_PREALLOC)
    // 如果新長度小于 SDS_MAX_PREALLOC 
    // 那么為它分配兩倍于所需長度的空間
    newlen *= 2;
  else
    // 否則,分配長度為目前長度加上 SDS_MAX_PREALLOC
    newlen += SDS_MAX_PREALLOC;
  // T = O(N)
  newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);

  // 內(nèi)存不足,分配失敗,返回
  if (newsh == NULL) return NULL;

  // 更新 sds 的空余長度
  newsh->free = newlen - len;

  // 返回 sds
  return newsh->buf;
}

      從圖中可以看出,當(dāng)要添加的內(nèi)容比目標(biāo)sds對象的free屬性要短時直接返回并將要添加的內(nèi)容添加到目標(biāo)sds對象的buf數(shù)組中即可;當(dāng)要添加的內(nèi)容比目標(biāo)sds對象的free屬性要長時,就會計算要添加的內(nèi)容和sds對象的當(dāng)前長度的和newlen,如果newlen小于SDS_MAX_PREALLOC也即1M的時候,新創(chuàng)建的buf數(shù)組的長度為newlen的兩倍,如果newlen大于SDS_MAX_PREALLOC的時候,新創(chuàng)建的buf數(shù)組的長度為newlen+SDS_MAX_PREALLOC,即只多分配1M的預(yù)留空間。空間預(yù)分配保證了sds對象的空余位長度至多為擴張之后字符串長度的1倍,這也就保證了后續(xù)對sds對象的修改將盡可能少的分配空間。

      惰性空間釋放指的是當(dāng)對一個sds對象進行縮短操作時,其不會直接將buf數(shù)組縮短為目標(biāo)數(shù)組的長度,而是只改變sds對象的len屬性的值,數(shù)組中多余的部分則保存在free屬性中,這樣就可以保證后續(xù)可能的對該sds對象的增長操作不需要重新分配空間。

      最后需要進行說明的是,sds對象也和c一樣使用“\0”作為字符串的結(jié)尾的原因是redis也是使用c語言編寫的,使用“\0”結(jié)尾就可以直接使用部分c函數(shù)庫中對字符串操作的函數(shù)。

      通過上面對sds對象的說明可以發(fā)現(xiàn),redis對sds對象的處理極大的減少了字符串處理中可能出現(xiàn)的復(fù)雜操作,并且大部分操作基本上都可以在極短的時間內(nèi)完成,這就保證了redis對字符串處理的高速率。

       感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

相關(guān)文章

  • Redis7.0部署集群的實現(xiàn)步驟

    Redis7.0部署集群的實現(xiàn)步驟

    本文主要介紹了Redis7.0部署集群的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Redis中Lua腳本的使用和設(shè)置超時

    Redis中Lua腳本的使用和設(shè)置超時

    本文將介紹Redis中Lua腳本的基本用法,以及腳本超時導(dǎo)致的問題和處理方式。文中通過示例代碼介紹的非常詳細(xì),感興趣的小伙伴們可以參考一下
    2021-11-11
  • php安裝redis擴展過程介紹

    php安裝redis擴展過程介紹

    大家好,本篇文章主要講的是php安裝redis擴展過程介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 解決redis修改requirepass后不生效的問題

    解決redis修改requirepass后不生效的問題

    今天小編就為大家分享一篇解決redis修改requirepass后不生效的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • 使用SpringBoot?+?Redis?實現(xiàn)接口限流的方式

    使用SpringBoot?+?Redis?實現(xiàn)接口限流的方式

    這篇文章主要介紹了SpringBoot?+?Redis?實現(xiàn)接口限流,Redis?除了做緩存,還能干很多很多事情:分布式鎖、限流、處理請求接口冪等,文中給大家提到了限流注解的創(chuàng)建方式,需要的朋友可以參考下
    2022-05-05
  • 詳解三分鐘快速搭建分布式高可用的Redis集群

    詳解三分鐘快速搭建分布式高可用的Redis集群

    這篇文章主要介紹了詳解三分鐘快速搭建分布式高可用的Redis集群,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • redis發(fā)布訂閱模式的實現(xiàn)

    redis發(fā)布訂閱模式的實現(xiàn)

    本文主要介紹了redis發(fā)布訂閱模式,Redis?的?SUBSCRIBE?命令可以讓客戶端訂閱任意數(shù)量的頻道,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • 關(guān)于Redis最常見的十道面試題總結(jié)大全

    關(guān)于Redis最常見的十道面試題總結(jié)大全

    Redis作為一個高性能的內(nèi)存數(shù)據(jù)存儲系統(tǒng),具有快速讀寫、持久性、數(shù)據(jù)結(jié)構(gòu)多樣性等特點,廣泛應(yīng)用于各種應(yīng)用場景,這篇文章主要給大家介紹了關(guān)于Redis最常見的十道面試題總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2024-07-07
  • jwt+redis實現(xiàn)登錄認(rèn)證的示例代碼

    jwt+redis實現(xiàn)登錄認(rèn)證的示例代碼

    在登錄業(yè)務(wù)代碼中,當(dāng)用戶登錄成功時,生成一個登錄憑證存儲到redis中,本文主要介紹了jwt+redis實現(xiàn)登錄認(rèn)證的示例代碼,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • 關(guān)于使用IDEA的springboot框架往Redis里寫入數(shù)據(jù)亂碼問題

    關(guān)于使用IDEA的springboot框架往Redis里寫入數(shù)據(jù)亂碼問題

    這篇文章主要介紹了用IDEA的springboot框架往Redis里寫入數(shù)據(jù)亂碼問題,本文給大家分享解決方法通過圖文示例相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10

最新評論