最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解析Redis 數(shù)據(jù)結(jié)構(gòu)之簡(jiǎn)單動(dòng)態(tài)字符串sds

 更新時(shí)間:2021年11月29日 09:37:04   作者:小碼code  
Redis 的 string 類型為何使用sds而不是 C 字符串,本文主要介紹 string 的數(shù)據(jù)結(jié)構(gòu)—— 簡(jiǎn)單動(dòng)態(tài)字符串(Simple Dynamic String) 簡(jiǎn)稱sds的相關(guān)知識(shí),需要的朋友可以參考下

Redis是用ANSI C語(yǔ)言編寫的,它是一個(gè)高性能的key-value數(shù)據(jù)庫(kù),它可以作用在數(shù)據(jù)庫(kù)、緩存和消息中間件。其中 Redis 鍵值對(duì)中的鍵都是 string 類型,而鍵值對(duì)中的值也是有 string 類型,在 Redis 中 string 類型運(yùn)用還是很廣泛的。本文主要介紹 string 的數(shù)據(jù)結(jié)構(gòu)—— 簡(jiǎn)單動(dòng)態(tài)字符串(Simple Dynamic String) 簡(jiǎn)稱sds。

sds 實(shí)現(xiàn)

sds 的數(shù)據(jù)結(jié)構(gòu):

struct sdshdr {

     //buf 已占用的長(zhǎng)度
     int len;

     // buf 剩余的可用的長(zhǎng)度
     int free;
   
     // 保存字符串?dāng)?shù)據(jù)的地方
     char buf[]; 
}

結(jié)構(gòu) sdshdr 保存了 len、free 和 buf 三個(gè)屬性,分別記錄字符的已使用的長(zhǎng)度,未使用的長(zhǎng)度,以及實(shí)際保存字符串的數(shù)組。
以下是一個(gè)新建的,保存 hello world 字符串的 sdshdr 結(jié)構(gòu):

struct sdshdr {
    len = 5;
    free = 0;
    buf = "hello\0"; 
}
  • free 屬性值為0,表示這個(gè)sds沒(méi)有分配未使用的空間。
  • len 屬性值為5,表示這個(gè)sds保存了一個(gè)五字節(jié)長(zhǎng)的字符串。
  • buf 屬性是一個(gè) char 類型的數(shù)組,數(shù)組的前五個(gè)字節(jié)分別保存了 'h'、'e'、'l'、'l'、'o' 五個(gè)字符,而最后一個(gè)字節(jié)保存了空字符'\0'。

sds 遵守 C 字符串以空字符串結(jié)尾的慣例,保存的空字符串一個(gè)字節(jié)空間不計(jì)算在 sds 的 len 屬性里面。添加空字符串到字符串末尾等操作,都是由 sds 函數(shù)自動(dòng)完成的,所以這個(gè)空字符對(duì)于使用者來(lái)說(shuō)完全是透明的。

通過(guò) len 屬性,可以實(shí)現(xiàn)時(shí)間復(fù)雜度 O(1) 的長(zhǎng)度計(jì)算。另外通過(guò)對(duì) buf 分配一些額外的空間,并使用 free 記錄未使用空間的長(zhǎng)度,sdshdr 可以減少內(nèi)存的重新分配。這是 sds 相對(duì) c 字符串的一個(gè)優(yōu)勢(shì)。

為何 Redis 不用 C 語(yǔ)言表示字符串

Redis 是使用 C 語(yǔ)言開(kāi)發(fā)的,而在使用最多的字符串上,Redis 沒(méi)有使用 C 語(yǔ)言傳統(tǒng)的字符串表示,而且使用自己構(gòu)建的簡(jiǎn)單動(dòng)態(tài)字符串(sds)。
在 C 語(yǔ)言中,字符串可以用一個(gè) \0 結(jié)尾的 char 數(shù)組表示。比如 hello world 在 C 語(yǔ)言中就可以表示為"hello world\0"。數(shù)組一般初始化以后長(zhǎng)度就已經(jīng)固定了,不能支持字符串追加append和長(zhǎng)度計(jì)算操作:

  • 每次計(jì)算字符串長(zhǎng)度都要遍歷一遍數(shù)組,所以時(shí)間復(fù)雜度是O(N)
  • 對(duì)字符串每次進(jìn)行追加操作,需要對(duì)字符串進(jìn)行一次內(nèi)存分配

sds 優(yōu)化追加字符操作

Redis 作為數(shù)據(jù)庫(kù),對(duì)于查詢速度要求嚴(yán)格,數(shù)據(jù)修改也比較頻繁,如果每次修改字符串都需要執(zhí)行一次內(nèi)存分配的話,都會(huì)占用大量的時(shí)間。所以 Redis 選擇了 sds 而不是 C 字符串,sds 可以減少追加字符的內(nèi)存分配。通過(guò)舉例來(lái)說(shuō)明,執(zhí)行以下操作時(shí),sds 內(nèi)部的變化:

redis> set msg "hello world"
OK

redis> append msg " again"
(integer)18

redis> get msg
"hello world again"

首先 set 命令創(chuàng)建并保存hello world 到一個(gè) sdshdr 中,這個(gè) sdshdr 的值如下:

struct sdshdr {
     len = 11;
     free = 0;
     buf = "hello world\0";
}

當(dāng)執(zhí)行 append 命令時(shí),相對(duì)應(yīng)的 sdshdr 被更新,字符串 " again" 會(huì)被追加到原來(lái)的 "hello world" 之后:

struct sdshdr {
     len = 17;
     free = 17;
     buf = "hello world again\0                ";
}

當(dāng)調(diào)用 set 命令創(chuàng)建 sdshdr 時(shí),Redis 沒(méi)有給 sdshdr 分配多余的空間,free 屬性為0。而在執(zhí)行 append 操作之后,Redis 為 buf 分配了多于所需空間一倍的大小。

在執(zhí)行 append 命令之后,保存 "hello world again" 共需要17 + 1 個(gè)字節(jié),但是程序?yàn)?sdshdr 分配了 17 + 17 + 1 = 35 個(gè)字節(jié),而后續(xù)如果在對(duì) sdshdr 進(jìn)行追加操作,只要追加的長(zhǎng)度不超過(guò) free 屬性值,那么就不需要對(duì) buf 進(jìn)行內(nèi)存重分配。

比如執(zhí)行以后命令并不會(huì)引起 buf 的內(nèi)存重分配,因?yàn)樾伦芳拥淖址L(zhǎng)度小于17:

redis> append msg  " again"
(integer) 23

對(duì)應(yīng)的 sdshdr 結(jié)構(gòu)如下:

struct sdshdr {
     len = 23;
     free = 11;
     buf = "hello world again again\0               ";
}

redis 內(nèi)存分配可以查看源碼 sds.s/sdsMakeRoomFor,sdsMakeRoomFor 函數(shù)描述了內(nèi)存分配的策略,下面的該函數(shù)的偽代碼:

// sdshdr:追加前的字符
// addlen:追加字符串
sds sdsMakeRoomFor(sdshdr, addlen) {
   
    // 多余空間大于追加空間,無(wú)序再分配內(nèi)存,直接返回
    if (free >= addlen) return s;
    // 計(jì)算新字符的長(zhǎng)度
    newlen = (len+addlen); 
   // 如果新字符的長(zhǎng)度小于 SDS_MAX_PREALLOC,就分配兩倍新字符空間
  //  如果新字符的長(zhǎng)度大于 SDS_MAX_PREALLOC,就分配新字符空間 + SDS_MAX_PREALLOC 空間
    if (newlen < SDS_MAX_PREALLOC)
        newlen *= 2;
    else
        newlen += SDS_MAX_PREALLOC;
    // 分配內(nèi)存
    newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);
    // 更新 free 屬性
    newsh.free = newlen - len;
    return newsh;
}

而對(duì)于字符的縮短操作,Redis 保存縮短后的字符串,此時(shí)并不會(huì)進(jìn)行內(nèi)存重分配,而是使用 free 屬性記錄縮短的字符長(zhǎng)度。

總結(jié)

Redis 的 string 類型為何使用sds而不是 C 字符串,因?yàn)閟ds有兩點(diǎn)優(yōu)勢(shì):

  • 計(jì)算字符長(zhǎng)度,C 字符串復(fù)雜度O(n),而 sds 復(fù)雜度為 O(1)
  • 字符追加操作,C 字符串每次都需要對(duì)內(nèi)存進(jìn)行重分配,而 sds 每次會(huì)進(jìn)行動(dòng)態(tài)擴(kuò)容,當(dāng)添加字符小于空閑字符時(shí),不會(huì)對(duì)內(nèi)容進(jìn)行分配,減少系統(tǒng)等待時(shí)間

參考

Redis 設(shè)計(jì)與實(shí)現(xiàn)

到此這篇關(guān)于深入理解Redis 數(shù)據(jù)結(jié)構(gòu)—簡(jiǎn)單動(dòng)態(tài)字符串sds的文章就介紹到這了,更多相關(guān)Redis 數(shù)據(jù)結(jié)構(gòu)動(dòng)態(tài)字符串sds內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Linux安裝單機(jī)版Redis的完整步驟

    Linux安裝單機(jī)版Redis的完整步驟

    這篇文章主要給大家介紹了關(guān)于Linux安裝單機(jī)版Redis的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • 解決redis在linux上的部署的問(wèn)題

    解決redis在linux上的部署的問(wèn)題

    這篇文章主要介紹了redis在linux上的部署,本文分步驟給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • Redis中序列化的兩種實(shí)現(xiàn)

    Redis中序列化的兩種實(shí)現(xiàn)

    本文主要介紹了Redis中序列化的兩種實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • Redis中set類型實(shí)現(xiàn)交集并集差集

    Redis中set類型實(shí)現(xiàn)交集并集差集

    本文主要介紹了Redis中set類型實(shí)現(xiàn)交集并集差集,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • redis分布式鎖實(shí)現(xiàn)示例

    redis分布式鎖實(shí)現(xiàn)示例

    本文主要介紹了redis分布式鎖實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-11-11
  • Redis集群部署Windows版本的過(guò)程詳解

    Redis集群部署Windows版本的過(guò)程詳解

    本文介紹了如何在Windows系統(tǒng)上部署Redis集群,包括從GitHub下載Windows版本的Redis、配置文件的創(chuàng)建、啟動(dòng)腳本的編寫以及集群的啟動(dòng)和配置過(guò)程,感興趣的朋友一起看看吧
    2025-03-03
  • Redis中AOF與RDB持久化策略深入分析

    Redis中AOF與RDB持久化策略深入分析

    Redis作為一款內(nèi)存數(shù)據(jù)庫(kù),因?yàn)槭莾?nèi)存讀寫,所以性能很強(qiáng),但內(nèi)存存儲(chǔ)是易失性的,斷電或系統(tǒng)奔潰都會(huì)導(dǎo)致數(shù)據(jù)丟失,因此Redis也需要將其數(shù)據(jù)持久化到磁盤上面,當(dāng)Redis服務(wù)重啟時(shí),會(huì)把磁盤上的數(shù)據(jù)再加載進(jìn)內(nèi)存,Redis提供了兩種持久化機(jī)制-RDB快照和AOF日志
    2022-11-11
  • Redis持久化解讀

    Redis持久化解讀

    Redis是一種內(nèi)存級(jí)數(shù)據(jù)庫(kù),提供高速讀寫性能,但數(shù)據(jù)易失,它支持三種持久化方式:RDB(快照持久化)、AOF(追加文件持久化)和混合持久化,RDB通過(guò)快照將數(shù)據(jù)保存到磁盤,AOF記錄所有寫操作命令,混合持久化結(jié)合兩者優(yōu)點(diǎn)
    2025-01-01
  • 詳解Spring?Boot?訪問(wèn)Redis的三種方式

    詳解Spring?Boot?訪問(wèn)Redis的三種方式

    這篇文章主要介紹了Spring?Boot?訪問(wèn)Redis的三種方式,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • Redis過(guò)期刪除策略與內(nèi)存淘汰策略

    Redis過(guò)期刪除策略與內(nèi)存淘汰策略

    這篇文章主要介紹了Redis過(guò)期刪除策略與內(nèi)存淘汰策略,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容戒殺,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09

最新評(píng)論

峨眉山市| 木里| 墨脱县| 如东县| 库尔勒市| 砀山县| 东安县| 洛隆县| 宁南县| 龙川县| 江门市| 醴陵市| 永丰县| 绥德县| 河东区| 甘孜县| 棋牌| 千阳县| 瑞昌市| 五家渠市| 奈曼旗| 无为县| 光泽县| 大丰市| 峨眉山市| 蒙自县| 页游| 沙河市| 聂拉木县| 梁山县| 新宁县| 临江市| 淮北市| 南充市| 西平县| 高邮市| 湟中县| 康定县| 吴江市| 禄劝| 潞西市|