---
有个统计页面的页面, 数据是存在redis有序集合里, score 是日期, 成员是统计的结果。 现在遇到一个问题, 当天的统计结果需要每隔几秒要更新一次。 但是有序集合不能根据score去更新成员的值, 需要根据socre找到成员, 然后再删除成员,再添加回score 和成员。再删除成员期间,还未添加回更新的值时, 有客户端查询的话, 就会少看到一条统计结果, 这要怎么解决?
```
script := `
local zset_key = KEYS[1]
local old_member = ARGV[1]
local new_score = ARGV[2]
local new_member = ARGV[3]
-- 删除旧的成员
redis.call('ZREM', zset_key, old_member)
-- 添加新的成员
redis.call('ZADD', zset_key, new_score, new_member)
return true
`
// 执行 Lua 脚本
_, err := g.Redis("cache4").Do("EVAL", script, 1, "your_zset_key", "old_member", updated_score, "new_member")
if err != nil {
fmt.Println("Error in Lua script:", err)
}
```
### 关键点
1. **原子性**:Lua 脚本在 Redis 内部执行时是原子操作,这意味着所有命令会连续执行,期间不会被其他操作打断。
2. **避免不一致性**:通过将 `ZREM` 和 `ZADD` 封装在同一个脚本中执行,可以避免删除成员期间有客户端查询到不完整数据的情况。
### Lua 脚本的工作流程:
1. 先执行 `ZREM` 删除旧成员。
2. 然后执行 `ZADD` 添加新成员,确保删除和添加操作在同一个原子操作中执行。
由于 Lua 脚本执行期间没有任何其他命令能够干扰,因此你可以确保没有其他客户端会在删除和重新添加成员的时间点进行查询,从而避免数据不一致。
---
- 可视化工具: Redis Insight
- Redis Desktop Manager
---
- 删除一个score
- DoVar("ZRANGEBYSCORE", "ladder:limit_up_count", score, score)
取出对应score的成员
- 删除成员
- DoVar("ZREM", "ladder:limit_up_count", delSCORE.Maps()[0])
---
- ZRANGEBYSCORE ladder:limit_up_count:1110 (20240911 +inf LIMIT 0 1
- ZREVRANGEBYSCORE ladder:limit_up_count:1110 (20240911 -inf LIMIT 0 1
~~~
data1, err := g.Redis("cache4").DoVar("ZRANGEBYSCORE", "ladder:limit_up_count:"+binaryStr, "+inf", "("+score, "LIMIT", 0, 1)
if err != nil {
return nil, nil, nil, nil, err
}
data2, err := g.Redis("cache4").DoVar("ZREVRANGEBYSCORE", "ladder:limit_up_count:"+binaryStr, score, "-inf", "LIMIT", 0, 11)
if err != nil {
return nil, nil, nil, nil, err
}
~~~
在 Go 中,`float32` 类型的值可以是 `NaN`(Not-a-Number),表示一个未定义或无法表示的数字。这通常会出现在无效的数学操作中,例如:
1. 0 除以 0 (`0/0`)
2. 开平方负数 (`math.Sqrt(-1)`)
3. 对 `NaN` 进行数学操作
### 检查 `NaN` 的情况
Go 提供了内置函数 `math.IsNaN` 来判断一个 `float32` 或 `float64` 值是否为 `NaN`。不过,对于 `float32` 你可以先将它转换为 `float64` 再使用此方法。
### 例子:
~~~
go复制代码package main
import (
"fmt"
"math"
)
func main() {
// 引发 NaN 的情况
var a float32 = float32(0) / float32(0)
fmt.Println("a:", a)
// 检查是否是 NaN
if math.IsNaN(float64(a)) {
fmt.Println("a 是 NaN")
} else {
fmt.Println("a 不是 NaN")
}
}
~~~
### 输出:
~~~
r复制代码a: NaN
a 是 NaN
~~~
### 触发 `NaN` 的常见情况:
1. **除以零:**
~~~
go复制代码var a float32 = 0 / 0
~~~
2. **负数的平方根:**
~~~
go复制代码var a float32 = float32(math.Sqrt(-1))
~~~
3. **`NaN` 传播:** 如果你对 `NaN` 进行任何数学操作,结果也会是 `NaN`。比如:
~~~
go复制代码var a float32 = float32(0) / float32(0)
var b float32 = a + 1 // b 也是 NaN
~~~
请注意,当进行一些无效数学运算时,`NaN` 是一个标准表示,程序本身不会崩溃或抛出异常,但计算结果会产生 `NaN`。
---
---
~~~go
type Person struct {
age int
}
func main() {
person := &Person{28}
// 1.
defer fmt.Println(person.age)
// 2.
defer func(p *Person) {
fmt.Println(p.age)
}(person)
// 3.
defer func() {
fmt.Println(person.age)
}()
person.age = 29
}
~~~
```
### 答案解析:
参考答案及解析:29 29 28。变量 person 是一个指针变量 。
1.person.age 此时是将 28 当做 defer 函数的参数,会把 28 缓存在栈中,等到最后执行该 defer 语句的时候取出,即输出 28;
2.defer 缓存的是结构体 Person{28} 的地址,最终 Person{28} 的 age 被重新赋值为 29,所以 defer 语句最后执行的时候,依靠缓存的地址取出的 age 便是 29,即输出 29;
3.很简单,闭包引用,输出 29;
又由于 defer 的执行顺序为先进后出,即 3 2 1,所以输出 29 29 28。
```
- Golang
- 切片 slice
- 数组和切片的区别
- 左闭右开
- make([]int, 5) 和 make([]int, 0, 5) 区别
- 切片非线程安全,并发操作为啥不会像map一样报错
- []struct{} 如何遍历
- 切片如何删除某个元素
- append 一个nil 切片
- 哈希表 map
- 并发操作
- 并发写报错
- 并发读不会报错
- 并发读有写报错
- 并发迭代有写报错
- 自制并发安全字典
- 官方并发安全字典
- 对未初始化的 map 进行赋值操作
- map的底层
- 无序输出
- 等量扩容
- 实现集合
- map的key可以使哪些值
- 协程 go
- 协程相关阅读
- 进程、线程、协程
- 协程 (捕获异常 和 协程池)
- GPM 模型
- CSP模型
- channel
- channel 相关操作
- 交替打印
- 如何让channel 只能接收/只能发送
- channel 常见报错
- channel 死锁
- nil channel 和 已关闭的 channel
- 使用 select 来多路复用 channel
- channel 的使用
- 接口和结构体
- 简单使用
- 两个结构体能否比较
- 工厂模式
- 概念
- 简单工厂
- 方法工厂
- 堆和栈,值类型和引用类型,内存逃逸,垃圾回收
- 栈和堆
- 内存逃逸
- 值类型和引用类型
- 垃圾回收方式
- 性能优化分析工具 pprof
- golang 代码片段
- 片段一 defer
- 片段二 channel
- Golang 相关
- Golang 相关阅读
- Golang 1-10
- make 和 new 的区别
- 使用指针的场景
- Go语言的context包
- 位运算
- Copy 是浅拷贝还是深拷贝
- init 函数 和 sync.Once
- select 多路复用
- Golang 其它
- MongoDB
- 可比较类型 与 可转json 类型
- Gorm
- 面向对象和面向过程
- go语言实现-面向对象
- go语言实现-面向过程
- 限流,熔断,降级
- 了解
- 熔断配置
- 熔断例子
- 服务降级
- github.com/alibaba/sentinel-golang
- 互斥锁 读写锁 原子锁
- 为什么需要锁
- 互斥锁
- 读写锁
- 原子锁
- 互斥锁性能对比
- 原子锁性能对比
- 互斥锁 or 原子锁?
- 条件锁
- 计数器
- GoFrame
- GF1.16版本
- 修改使用的表
- 按天、周、月、年
- GoFrame 文档
- 配置文件
- 生成脚本
- 排序算法
- 相关排序
- 冒泡排序
- 选择排序
- 插入排序
- 快速排序
- 归并排序
- 堆排序
- 数据库
- 分布式怎么保证线程安全
- 数据库实现方式
- 基于表记录
- 乐观锁
- 悲观锁
- Redis实现方式
- Zookeeper实现方式
- Mysql 相关
- group_concat
- 索引优化
- 索引优化1
- 定期分析和优化索引
- 覆盖索引
- 组合索引
- 聚簇索引和非聚簇索引
- 索引类型与方式、聚簇与非聚簇索引
- 事务特征和隔离级别
- 查询优化
- mysql自增表插入数据时,Id不连续问题
- InnoDB引擎 和 MyISAM引擎区别
- 锁
- 悲观锁和乐观锁
- 查询,更新,插入语句
- 什么是死锁
- 怎么处理死锁
- MySQL 隔离级别
- 事务特征
- 隔离级别
- 废弃3
- 索引
- 索引类型和方式、聚簇和非聚簇索引(上)
- 索引类型和方式、聚簇和非聚簇索引(下)
- 回表、覆盖索引、最左前缀、联合索引、索引下推、索引合并
- Mysql 优化
- 索引的原理
- 千万级表修改表结构
- Redis
- 获取随机三条数据
- Redis 持久化方式
- 全量模式 RDB 冷备份(内存快照)
- 增量模式 AOF 热备份(文件追加)
- 过期key的删除策略、内存淘汰机制
- 数据结构
- 位图
- 网络
- 网络相关
- 游戏同步方式:帧同步和状态同步
- Websocket
- OSI模型
- TCP 与 UDP
- 三次握手四次挥手
- Http 状态码
- 1xx(信息性状态码)
- 101 服务端代码
- 101 客户端代码
- 2xx(成功状态码)
- 3xx(重定向状态码)
- 302 服务端代码
- 302 客户端代码
- 4xx(客户端错误状态码)
- 5xx(服务器错误状态码)
- 如何排查接口问题
- 网络请求和响应过程
- time_wait
- keep-alive
- http 和 rpc 的区别
- I/O多路复用 select和poll
- too many open file
- 其它技术
- git 相关操作
- 修改提交备注
- 多个提交合并成一个提交
- 回退版本
- 小程序和公众号
- 消息模板
- 获取code
- 静默登录
- 其它技术相关
- C盘空间不足
- 生成式人工智能AIGC
- 共享文件
- 接口文档, mock提供测试数据
- 抓包工具
- Python
- 安装包失败
- 自动化测试 Scrapy
- AIGC:人工智能生成内容
- PHP
- xhprof 性能分析
- 一键安装
- 哈希冲突的解决方式
- 链地址法(拉链法)
- 开放地址法
- 再哈希
- 概念1
- Nginx
- 负载均衡方式
- 加密解密
- 简单了解
- 签名算法例子
- 码例子1
- 代码例子2
- Linux
- netstat (用于查看和管理网络连接和路由表)
- ps 用于查看和管理进程
- ab 压测
- nohup 守护进程
- lsof (List Open File 获取被进程打开文件的信息)
- tail 查看日志
- 各类linux同步机制
- Socket 服务端的实现,select 和epoll的区别?
- scp 传输,awk 是一个强大的文本分析工具
- pidof
- 项目
- 棋牌
- 牌的编码
- 出牌规则
- 洗牌
- 股票
- 股票知识
- 龙虎榜数据缓存方式
- 单日龙虎榜数据
- 单只股票的历史上榜
- 遇到的问题
- 浮点数精度问题
- Mysql Sum 精度问题(float, double精度问题)
- 分页问题(数据重复)
- 工具包
- v3
- common.go
- common_test.go
- customized.go
- customized_test.go
- slice.go
- slice_test.go
- time.go
- time_test.go
- v4
- common.go
- common_test.go
- customized.go
- customized_test.go
- slice.go
- time.go
- time_test.go
- 相关阅读
- 集合 map
- 协程 goroutine
- 通道 channel
- json 和 gob 序列化和反序列化
- redis 有序集合
- 相关阅读 s
- pyTorch
- defer
- 内存泄漏
- 数据传输
- 杂项
- 一提