发现一个 golang 结构体字段被异常修改的问题,大家帮我看看

2023-02-24 11:42:17 +08:00
 Wangds

简单描述,就是在内存保存数据,在创建和查询过程中,某些字段的值会在查询时意外的被改变,改变的方式也很奇怪。

例如存在一个结构体 Task 和一个全局变量 list:

var list sync.Map
type Task struct {
    ID int64
    Name string
    User string
}

创建并把 task 保存在全局变量 list 中;

task := Task {
    ID: now.UnixMicro(),
    Name: "agent-web",
    User: "wangds",
}
list.Store(task.Name, task)

执行查询时,task 的值可会意外的改变,发生概率盲猜有 0.1-0.4 ; 而且每次更改代码后,只遵循以下 5 种改变模式中的 1 种:

{
    ID: 1677200690411702,
    Name: "agent-web",
    User: "agent-",
}
{
    ID: 1677200690411702,
    Name: "1gent-web",
    User: "wangds",
}
{
    ID: 1677200690411702,
    Name: "agent-web",
    User: "1angds",
}
{
    ID: 1677200690411702,
    Name: "agent-web",
    User: "167720",
}
{
    ID: 1677200690411702,
    Name: "167720069",
    User: "wangds",
}

全局变量试过其他类型,比如 map 、slice ,还试过一个第三方的内存缓存工具 ristretto ,都有这个问题。

https://gitee.com/tianshuapp/web-deploy-task-manage

2037 次点击
所在节点    Go 编程语言
40 条回复
rrfeng
2023-02-24 11:45:32 +08:00
逻辑都没写全,怎么判断哪里有问题……
pathletboy
2023-02-24 11:46:22 +08:00
所有更新数据的地方打 LOG 嘛,很快就能找到。
Wangds
2023-02-24 11:48:31 +08:00
@rrfeng 文章底部有代码,可以复现
Wangds
2023-02-24 11:49:39 +08:00
@pathletboy 有在协程里持续打印,发现是查询的一瞬间改变的,但是不知道为什么会改变
dcalsky
2023-02-24 11:49:53 +08:00
帮你看看 != 帮你 review 整个项目,你发个 repo 的链接是要闹哪样
john2022
2023-02-24 11:50:07 +08:00
使用内存地址而不是值试试
Wangds
2023-02-24 11:52:09 +08:00
@dcalsky 不是整个项目啊,是创建和查询的最小实现。
Wangds
2023-02-24 11:53:02 +08:00
@john2022 我再试试,当时好像也试过指针
john2022
2023-02-24 11:56:17 +08:00
另外,你这个 list 和 list2 是 package 私有变量,不是全局变量
john2022
2023-02-24 11:57:33 +08:00
全局变量最好使用 func init 来初始化,并且最好用大写的,比如 TaskList TaskList1 ,对 list 的修改使用锁,否则有可能会被清除
Maboroshii
2023-02-24 12:03:37 +08:00
你的 map key 为什么是 Name 而不是 ID ?
Wangds
2023-02-24 12:05:12 +08:00
@Maboroshii 我记得用 ID 也会变
Wangds
2023-02-24 12:06:38 +08:00
@john2022 是要把 list 和 list2 放到 main 包里吗
anerevol
2023-02-24 12:09:46 +08:00
你这创建 task 的时候,判断同名的 task 是否存和创建 task 不是原子操作吧
john2022
2023-02-24 12:11:13 +08:00
model 里创建 func init(){
}
在 main 里面使用 import _ "web-deploy-task-manage/model"
john2022
2023-02-24 12:11:59 +08:00
@anerevol 应该是线程不安全,所以要使用读写锁
Wangds
2023-02-24 12:12:25 +08:00
@anerevol 以前有个版本是加了锁的,也有这个问题。我给代码加个延时试试
echoless
2023-02-24 12:13:44 +08:00
老弟问题能不能在一个文件里面复现
Wangds
2023-02-24 12:15:55 +08:00
@anerevol 创建方法里查,判断同名代码后加了个延时;测试的代码里每次创建、查询、循环之间都加了延时;
肉眼可看的一个一个蹦日志,也会出现问题,哭了
Wangds
2023-02-24 12:16:22 +08:00
@wuhaoecho 我试试

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/918807

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX