Redis 位域
提示
来自deepseek解释
原文链接:https://redis.io/docs/latest/develop/data-types/strings/bitfields/
代码示例图例
下面的代码示例展示了如何在不同编程语言和客户端库中执行相同的操作:
- Redis CLI:Redis 命令行界面
- C#(同步):StackExchange.Redis 同步客户端
- C#(异步):StackExchange.Redis 异步客户端
- Go:go-redis 客户端
- Java(同步 - Jedis):Jedis 同步客户端
- Java(异步 - Lettuce):Lettuce 异步客户端
- Java(响应式 - Lettuce):Lettuce 响应式/流式客户端
- JavaScript(Node.js):node-redis 客户端
- PHP:Predis 客户端
- Python:redis-py 客户端
- Rust(同步):redis-rs 同步客户端
- Rust(异步):redis-rs 异步客户端
每个代码示例都演示了不同语言中相同的基本操作。具体语法和模式因语言和客户端库而异,但底层的 Redis 命令和行为保持一致。
位图/位域命令摘要
本组共 7 条命令:
| 命令 | 摘要 | 复杂度 | 起始版本 |
|---|---|---|---|
| BITCOUNT | 计算字符串中被置位(人口计数)的数量。 | O(N) | 2.6.0 |
| BITFIELD | 对字符串执行任意的位域整数操作。 | 每个指定的子命令为 O(1) | 3.2.0 |
| BITFIELD_RO | 对字符串执行任意的只读位域整数操作。 | 每个指定的子命令为 O(1) | 6.0.0 |
| BITOP | 对多个字符串执行按位操作,并存储结果。 | O(N) | 2.6.0 |
| BITPOS | 查找字符串中第一个被置位(1)或清零(0)的位。 | O(N) | 2.8.7 |
| GETBIT | 按偏移量返回一个位的值。 | O(1) | 2.2.0 |
| SETBIT | 设置或清除字符串值在偏移量处的位。如果键不存在则创建它。 | O(1) | 2.2.0 |
Redis 位域允许您设置、递增和获取任意位长度的整数值。例如,您可以操作从无符号 1 位整数到有符号 63 位整数的任何内容。
这些值使用二进制编码的 Redis 字符串存储。位域支持原子读取、写入和递增操作,使其成为管理计数器和类似数值的绝佳选择。
示例
假设您想为各种自行车维护两个指标:当前价格和随时间变化的拥有者数量。您可以为每辆自行车使用一个 32 位宽的位域来表示这些计数器。
- 自行车 1 最初售价 1000(偏移量 0 处的计数器),并且从未有过拥有者。出售后,它现在被视为二手,价格立即下降以反映其新状况,并且现在有了一个拥有者(偏移量 1)。过了相当长的时间,这辆自行车成为了经典。原始拥有者将其出售获利,因此价格上涨,拥有者数量也增加。最后,您可以查看自行车当前的价格和拥有者数量。
位域操作:当需要高效管理多个计数器时,使用 BITFIELD 原子性地设置、递增和获取任意位长度的整数值
难度: 中级
命令: BITFIELD
复杂度:
- BITFIELD: O(1)
可用客户端: Redis CLI, Go, Java (同步 - Jedis), JavaScript (Node.js), Python
Redis CLI
> BITFIELD bike:1:stats SET u32 #0 1000
1) (integer) 0
> BITFIELD bike:1:stats INCRBY u32 #0 -50 INCRBY u32 #1 1
1) (integer) 950
2) (integer) 1
> BITFIELD bike:1:stats INCRBY u32 #0 500 INCRBY u32 #1 1
1) (integer) 1450
2) (integer) 2
> BITFIELD bike:1:stats GET u32 #0 GET u32 #1
1) (integer) 1450
2) (integer) 2Go
go
res1, err := rdb.BitField(ctx, "bike:1:stats",
"set", "u32", "#0", "1000",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res1) // >>> [0]
res2, err := rdb.BitField(ctx,
"bike:1:stats",
"incrby", "u32", "#0", "-50",
"incrby", "u32", "#1", "1",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res2) // >>> [950 1]
res3, err := rdb.BitField(ctx,
"bike:1:stats",
"incrby", "u32", "#0", "500",
"incrby", "u32", "#1", "1",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res3) // >>> [1450 2]
res4, err := rdb.BitField(ctx, "bike:1:stats",
"get", "u32", "#0",
"get", "u32", "#1",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res4) // >>> [1450 2]Java(同步 - Jedis)
java
List<Long> res1 = jedis.bitfield("bike:1:stats", "SET", "u32", "#0", "1000");
System.out.println(res1); // >>> [0]
List<Long> res2 = jedis.bitfield("bike:1:stats", "INCRBY", "u32", "#0", "-50", "INCRBY", "u32", "#1", "1");
System.out.println(res2); // >>> [950, 1]
List<Long> res3 = jedis.bitfield("bike:1:stats", "INCRBY", "u32", "#0", "500", "INCRBY", "u32", "#1", "1");
System.out.println(res3); // >>> [1450, 2]
List<Long> res4 = jedis.bitfield("bike:1:stats", "GET", "u32", "#0", "GET", "u32", "#1");
System.out.println(res4); // >>> [1450, 2]JavaScript(Node.js)
javascript
let res1 = await client.bitField("bike:1:stats", [{
operation: 'SET',
encoding: 'u32',
offset: '#0',
value: 1000
}]);
console.log(res1); // >>> [0]
let res2 = await client.bitField('bike:1:stats', [
{
operation: 'INCRBY',
encoding: 'u32',
offset: '#0',
increment: -50
},
{
operation: 'INCRBY',
encoding: 'u32',
offset: '#1',
increment: 1
}
]);
console.log(res2); // >>> [950, 1]
let res3 = await client.bitField('bike:1:stats', [
{
operation: 'INCRBY',
encoding: 'u32',
offset: '#0',
increment: 500
},
{
operation: 'INCRBY',
encoding: 'u32',
offset: '#1',
increment: 1
}
]);
console.log(res3); // >>> [1450, 2]
let res4 = await client.bitField('bike:1:stats', [
{
operation: 'GET',
encoding: 'u32',
offset: '#0'
},
{
operation: 'GET',
encoding: 'u32',
offset: '#1'
}
]);
console.log(res4); // >>> [1450, 2]Python
python
bf = r.bitfield("bike:1:stats")
res1 = bf.set("u32", "#0", 1000).execute()
print(res1) # >>> [0]
res2 = bf.incrby("u32", "#0", -50).incrby("u32", "#1", 1).execute()
print(res2) # >>> [950, 1]
res3 = bf.incrby("u32", "#0", 500).incrby("u32", "#1", 1).execute()
print(res3) # >>> [1450, 2]
res4 = bf.get("u32", "#0").get("u32", "#1").execute()
print(res4) # >>> [1450, 2]性能
BITFIELD 的复杂度为 O(n),其中 n 是访问的计数器数量。