主頁 > 資料庫 > Redis - 二進制位陣列

Redis - 二進制位陣列

2023-05-23 09:31:42 資料庫

簡介

Redis 使用字串物件來表示位陣列,因為字串物件使用的 SDS 資料結構是二進制安全的,所以程式可以直接使用 SDS 結構來保存位陣列,并使用 SDS 結構的操作函式來處理位陣列,

在 SDS 結構當中,buf 位元組陣列除了字串結尾的 \0 空字符,其余的位置都存盤著一個位元組長的位陣列,一個位元組可以存盤 8 位的二進制,

這里需要注意的是,在 buf 陣列中存盤的二進制位陣列的順序與實際書寫的順序相反,比如 01010101 存盤在 buf 陣列中的結構是 10101010 這樣的倒序,使用逆序來保存位陣列可以簡化 SETBIT 的實作,

命令使用

Redis 提供了 GETBITSETBITBITCOUNTBITOPBITPOSBITFIELDBITFIELD_RO 等命令用于處理二進制位陣列,

GETBIT

GETBIT <bitarray> <offset> 命令用于回傳位陣列 bitarrayoffset 偏移量上的二進制位的值,其詳細執行程序如下:

  1. 計算 byte = offset / 8 得到 offset 偏移量指定的二進制位保存在位陣列的哪個位元組;
  2. 計算 bit = (offset mod 8) + 1 得到 offset 偏移量指定的二進制位是 byte 位元組的第幾個二進制位;
  3. 根據 byte 值和 bit 值,在位陣列 bitarray 中定位 offset 偏移量指定的二進制位,并回傳這個位的值,

SETBIT

SETBIT <bitarray> <offset> <value> 可以看作是 GETBIT 的反向操作,只是需要注意設定二進制位時有可能需要擴展 buf 陣列的長度,

具體的執行程序如下:

  1. 計算 len = (offset / 8) + 1 得到保存 offset 偏移量指定的二進制位需要多少位元組;
  2. 檢查 bitarray 位陣列的長度是否滿足要求,否則需要對 SDS 的進行擴展,并且將新增的二進制位全部置為 0;
  3. 計算 byte = offset / 8 得到 offset 偏移量指定的二進制位保存在位陣列的哪個位元組;
  4. 計算 bit = (offset mod 8) + 1 得到 offset 偏移量指定的二進制位是 byte 位元組的第幾個二進制位;
  5. 根據 byte 值和 bit 值,在位陣列 bitarray 中定位 offset 偏移量指定的二進制位,首先將這個位現在的值保存在 oldvalue 變數中,然后將新值 value 設定為這個二進制位的值;
  6. 向客戶端回傳 oldvalue 的值,

由于 buf 陣列使用逆序保存位陣列,當 Redis 對 buf 陣列進行擴展之后,寫入操作都可以直接在新擴展的二進制位中完成,而不必改動位陣列原來已有的二進制位,

BITCOUNT

BITCOUNT key [start] [end] 命令用于統計給定位陣列中,值為 1 的二進制位的數量,

BITOP

BITOP operation destkey key [key ...] 支持對一個或多個保存二進制位的字串 key 進行位元操作,并將結果保存到 destkey 上,operation 可以是 ANDORNOTXOR 這四種操作中的任意一種:

  • AND: 邏輯與
  • OR: 邏輯或
  • NOT: 邏輯非
  • XOR: 邏輯異或

因為 BITOP ANDBITOP ORBITOP XOR 三個命令可以接受多個位陣列作為輸入,程式需要遍歷輸入的每個位陣列的每個位元組來進行計算,所以這些命令的復雜度為 \(O(n^2)\);與此相反,因為 BITOP NOT 命令只接受一個位陣列輸入,所以它的復雜度為 \(O(n)\)

BITPOS

BITPOS key bit [start [end [BYTE | BIT]]] 回傳字串中設定為 1 或 0 的第一個位的位置,

默認情況下,整個字串都會被檢索一遍,命令的

使用 startend 引數默認可以指定一個位元組的范圍,在 7.0.0 版本之后,提供了 BYTEBIT 指定以位元組為范圍還是位為范圍,

二進制位統計演算法

BITCOUNT 命令要做的作業初看上去并不復雜,但實際上要高效地實作這個命令并不容易,需要用到一些精巧的演算法,

遍歷演算法

實作 BITCOUNT 命令最簡單直接的方法,就是遍歷位陣列中的每個二進制位,并在遇到值為 1 的二進制位時,將計數器的值增一,

遍歷演算法雖然實作起來簡單,但效率非常低,因為這個演算法在每次回圈中只能檢查一個二進制位的值是否為 1,所以檢查操作執行的次數將與位陣列包含的二進制位的數量成正比,

查表演算法

查表演算法就是創建一個表,表的鍵為某種排列的位陣列,而表的值則是相應位陣列中值為 1 的二進制位的數量,

創建了這種表之后,就可以根據輸入的位陣列進行查表,在無須對位陣列的每個位進行檢查的情況下,直接知道這個位陣列包含了多少個值為 1 的二進制位,

初看起來,只要創建一個足夠大的表,那么統計作業就可以輕易地完成,但這個問題實際上并沒有那么簡單,因為查表法的實際效果會受到記憶體和快取兩方面因素的限制:

  • 查表法是典型的空間換時間策略,演算法在計算方面節約的時間是通過花費額外的記憶體換取而來的,節約的時間越多,花費的記憶體就越大,
  • 查表法的效果還會受到 CPU 快取的限制,對于固定大小的 CPU 快取來說,創建的表格越大,CPU 快取所能保存的內容相比整個表格的比例就越少,查表時出現快取不命中的情況就會越高,快取的換入和換出操作就會越頻繁,最終影響查表法的實際效率,

variable-precision SWAR 演算法

BITCOUNT 命令要解決統計一個位陣列中非 0 二進制位的數量的問題,在數學上被稱為“計算漢明重量(Hamming Weight)”,目前已知效率最好的通用演算法為 variable-precision SWAR 演算法,該演算法通過一系列位移和位運算操作,可以在常數時間內計算多個位元組的漢明重量,并且不需要使用任何額外的記憶體,

以下是一個處理 32 位長度位陣列的 variable-precision SWAR 演算法的實作:

uint32_t swar(uint32_t i){
    i = (i & 0x55555555) + ((i>>1) & 0x55555555);  // 步驟 1
    i = (i & 0x33333333) + ((i>>2) & 0x33333333);  // 步驟 2
    i = (i & 0x0F0F0F0F) + ((i>>4) & 0x0F0F0F0F);  // 步驟 3
    i = (i - 0x01010101) >> 24;                    // 步驟 4
    return i;
}

variable-precision SWAR 演算法實質上是通過分而治之的思想,將計算拆解成多個小問題去解決:

  1. 步驟 1 是將 32 位陣列與 01010101010101010101010101010101 做邏輯與操作,并且右移 1 位之后繼續做邏輯與操作,最終取它們的和,這一步的想法是將 32 位拆成每 2 位作為一個組合,統計出每一組中 1 的個數;
  2. 步驟 2 是將上述得到的結果與 00110011001100110011001100110011 做邏輯與操作,這一步的想法就是拆成每 4 位作為一個組合,統計出每一組中 1 的個數;
  3. 步驟 3 是將上述得到的結果與 00001111000011110000111100001111 做邏輯與操作,這一步的想法就是拆成每 8 位作為一個組合,統計出每一組中 1 的個數;
  4. 上述的結果仍然不是最終想要的結果,步驟 4 就是將上述得到的數字計算出 1 真正的數量,i - (0x01010101) 計算出漢明重量并記錄在二進制的高八位,>> 24 陳述句則通過右移運算,將漢明重量移到最低八位,最后二進制對應的十進制就是漢明重量,

計算漢明重量最后一步

因為 variable-precision SWAR 演算法是一個常數復雜度的操作,所以可以按照自己的需要,在一次回圈中多次執行 variable-precision SWAR 演算法,從而按倍數提升計算漢明重量的效率,

當然,在一個回圈里執行多個 variable-precision SWAR 演算法呼叫這種優化方式是有極限的:一旦回圈中處理的位陣列的大小超過了快取的大小,這種優化的效果就會降低并最終消失,

Redis 的實作

BITCOUNT 命令的實作用到了查表和 variable-precision SWAR 兩種演算法:

  • 如果未處理處理的二進制位的數量小于 128 位,那么程式使用查表演算法來計算二進制位的漢明重量,表中記錄了 0x00 ~ 0xFF 在內的所有二進制位的漢明重量
  • 如果未處理的二進制位的數量大于等于 128 位,那么程式使用 variable-precision SWAR 演算法來計算二進制位的漢明重量,每次處理 128 個二進制位,呼叫 4 次 32 位 variable-precision SWAR 演算法來計算其漢明重量

實際上 BITCOUNT 命令實作的演算法復雜度為 \(O(n)\),其中 n 為輸入二進制位的數量,

首發于「程式員翔仔」,點擊查看更多,

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/553136.html

標籤:NoSQL

上一篇:Redis單機部署

下一篇:返回列表

標籤雲
其他(159511) Python(38162) JavaScript(25443) Java(18096) C(15230) 區塊鏈(8267) C#(7972) AI(7469) 爪哇(7425) MySQL(7207) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5871) 数组(5741) R(5409) Linux(5340) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4574) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2433) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1975) 功能(1967) Web開發(1951) HtmlCss(1940) C++(1919) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1878) .NETCore(1861) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • Redis - 二進制位陣列

    數學上有一個“計算漢明重量”的問題,即求取一個二進制位中非 0 的數量。使用 Redis 提供的 Bitmap 統計時恰恰是這樣一個問題,學習后能發現解決辦法卻是如此巧妙。 ......

    uj5u.com 2023-05-23 09:31:42 more
  • Redis單機部署

    # Redis單機部署 ## 1 安裝 下載最新穩定版Redis https://download.redis.io/redis-stable.tar.gz ```shell # 安裝wget yum install -y wget # 安裝gcc環境 yum install gcc-c++ # 獲 ......

    uj5u.com 2023-05-23 09:31:34 more
  • 小白零基礎在 Centos 7 中安裝 mysql

    本文參考這三篇博文,安裝,修改配置,修改密碼。感謝大佬的分享 首先安裝好Centos,并使用xshell連接 一、下載 1、下載安裝檔案 建議自己到這個地址下載 https://dev.mysql.com/downloads/mysql/。選擇以下版本 2、下載完后上傳到系統,并解壓,可以用 tar ......

    uj5u.com 2023-05-23 09:31:17 more
  • 線上問題處理案例:出乎意料的資料庫連接池

    本文是線上問題處理案例系列之一,旨在通過真實案例向讀者介紹發現問題、定位問題、解決問題的方法。本文講述了從垃圾回收耗時過長的表象,逐步定位到資料庫連接池保活問題的全程序,并對其中用到的一些知識點進行了總結。 ......

    uj5u.com 2023-05-23 09:31:11 more
  • 為什么MySQL單表不能超過2000萬行?

    摘要:MySQL一張表最多能存多少資料? 本文分享自華為云社區《為什么MySQL單表不能超過2000萬行?》,作者: GaussDB 資料庫 。 最近看到一篇《我說MySQL每張表最好不要超過2000萬資料,面試官讓我回去等通知》的文章,非常有趣。 文中提到,他朋友在面試的程序中說,自己的作業就是把 ......

    uj5u.com 2023-05-23 09:29:41 more
  • MySQL 并行復制方案演進歷史及原理分析

    有過線上 MySQL 維護經驗的童鞋都知道,主從延遲往往是一個讓人頭疼不已的問題。



    不僅僅是其造成的潛在問題比較嚴重,而且主從延遲原因的定位尤其考量 DBA 的綜合能力:既要熟悉復制的內部原理,又能解讀主機層面的資源使用情況,甚至還要會分析 binlog。



    導致主從延遲的一個常見原因是,... ......

    uj5u.com 2023-05-22 08:39:29 more
  • 一次redis主從切換導致的資料丟失與陷入只讀狀態故障

    ## 背景 最近一組業務redis資料不斷增長需要擴容記憶體,而擴容記憶體則需要重啟云主機,在按計劃擴容升級執行主從切換時意外發生了資料丟失與master進入只讀狀態的故障,這里記錄分享一下。 ## 業務redis高可用架構 該組業務redis使用的是一主一從,通過sentinel集群實作故障時的自動主 ......

    uj5u.com 2023-05-22 08:23:33 more
  • 03、Etcd 客戶端常用命令

    上一講我們安裝 etcd 服務端,這一講我們來一起學學如何使用 etcd 客戶端常見的命令。文章內容來源于參考資料,如若侵權,請聯系洗掉,謝謝。 > etcd可通過客戶端命令列工具 etcdctl 對etcd進行請求操作 ```sh # 幫助命令,會列出所有的命令和選項,在記不太清命令的時候,可以使 ......

    uj5u.com 2023-05-22 08:23:27 more
  • es筆記四之中文分詞插件安裝與使用

    > 本文首發于公眾號:Hunter后端 > 原文鏈接:[es筆記四之中文分詞插件安裝與使用](https://mp.weixin.qq.com/s/aQuwrUzLZDKLv_K8dKeVzw) 前面我們介紹的操作及演示都是基于英語單詞的分詞,但我們大部分使用的肯定都是中文,所以如果需要使用分詞的操 ......

    uj5u.com 2023-05-22 08:23:21 more
  • 03、Etcd 客戶端常用命令

    上一講我們安裝 etcd 服務端,這一講我們來一起學學如何使用 etcd 客戶端常見的命令。文章內容來源于參考資料,如若侵權,請聯系洗掉,謝謝。 > etcd可通過客戶端命令列工具 etcdctl 對etcd進行請求操作 ```sh # 幫助命令,會列出所有的命令和選項,在記不太清命令的時候,可以使 ......

    uj5u.com 2023-05-22 08:22:58 more