首页 > 技术文章 > 位图

fromzore 2018-12-01 14:25 原文

参考书籍:《redis深度历险:核心原理与应用实践》

位图不是特殊的数据结构,它的内容其实就是普通的字符串,也就是byte数组。对于位图的存取,有零存零取,零存整取,整存零取3种方式。(整存整取直接就是字符串操作了)零存/取就是使用setbit/getbit对位值进行逐个设置;整存就是set使用字符串一次性填充所有位图,覆盖掉旧值;整取就是使用get一次性全部获取,输出的是字符串。

#给字符串w的key位置赋上具体的value值(0or1)
setbit w key value
#获取key位置的具体值
getbit w key
#整存覆盖
set w 'hello'
#整取
get w

redis的位图是自动扩展,如果设置了某个偏移位置超出了内容范围,就会自动将位图进行0扩充。就是说你第一位赋值1,然后直接第10位赋值是1,那么中间的几位的值全部自动扩充为0。

在整取时如果对应的字节是不可打印的字符,redis-cli会显示该字符的16进制形式。

redis提供了位图统计指令bitcount和位图查找指令bitpos

#统计区间[start,end]之间有多少位为1
bitcount w start end
#查找区间[start,end]之间的第一个1的位置
bitpos w start end

但是start和end参数是字节索引,也就是说指定的位范围必须是8的倍数。

Redis3.2版本以后新增了一个bitfield指令。

bitfield有三个子指令,分别是get/set/incry,他们都可以对指定指令定位片段进行读写,但是最多只能处理64个连续的值,如果超出64位,就得使用多个子指令。

#从第start+1个位开始,取number个数,输出为无符号数
bitfield w get unumber start
#从第start+1个位开始,取number个数,输出为有符号数
bitfield w get inumber start
#一次执行多个指令
bitfield w get inumber start get unumber start get inumber start...
#从第start个位开始,将接下来的number个位用无符号数sum替换
bitfield w set unumber start sum

 

第三个指令incrby是用来对指定范围的位进行自增操作的指令。对于自增,可能会出现溢出。(自增加的可以是正数,也可以是负数)。bitfield指令提供了溢出策略子指令。redis的默认处理是折返(warp),同时还有选择失败(fail)报错不执行,以及饱和截断(sat)子指令。

#默认折返从第start位开始,对接下来的number位无符号数进行加1
bitfield w incrby unumber start 1
#饱和截断
bitfield w overflow sat incrby unumber start 1
#失败不执行
bitfield w overflow fai incrby unumber start 1

 

 

还有我们计算机保存ascII码的时候,是由图的上一部分表示的那样,低位在左高位在右。setbit在读取每一位的时候,因为是位数组,保存时是由低位到高位。

在计算机中,我们保存二进制的方式是补码形式,比如说无符号类型的5,二进制是101,但是换成integer就是101,第一位1代表是负数,剩下01,输出的时候是对01减一再取反,就是11,输出就是-3.

 

推荐阅读