【发布时间】:2013-08-17 20:13:58
【问题描述】:
我想在将结构编组为 json 时将 RLock/RUnlock 添加到结构中。
下面的示例显示了我尝试做的事情。但是,它不起作用,因为每次调用json.Marshal,它都会运行Object.MarshalJSON方法,该方法本身调用json.Marshal,导致无限循环。
例子:
package main
import (
"fmt"
"encoding/json"
"sync"
)
type Object struct {
Name string
Value int
sync.RWMutex
}
func (o *Object) MarshalJSON() ([]byte, error) {
o.RLock()
defer o.RUnlock()
fmt.Println("Marshalling object")
return json.Marshal(o)
}
func main() {
o := &Object{Name: "ANisus", Value: 42}
j, err := json.Marshal(o)
if err != nil {
panic(err)
}
fmt.Printf("%s\n", j)
}
输出:
编组对象
编组对象
编组对象
...
显然,我可以在调用 json.Marshal 之前删除 MarshalJSON 方法并在主函数中调用 Lock()。但是,我的问题是:
有没有办法在结构的 MarshalJSON 方法中调用 json.Marshal(或者至少让 json 包处理编码)?
额外问题
为什么我的程序没有冻结?第二次递归调用 MarshalJSON 时,结构体不应该被锁定吗?
【问题讨论】:
-
为什么要锁定对象?
-
@Akira:如果我有多个 goroutine 共享对象,我想防止其他例程在编码时更改数据。在我的示例中,我没有那个,但该示例并不是为了显示实际用法。
-
取决于要编码的对象的大小:复制结构是一个有效的选项,恕我直言。
-
@Akira:复制结构不是原子操作。我仍然需要在复制期间锁定它以防止数据竞争。所以它仍然是同样的问题。
-
真的。不过,我考虑
time(copy(x)) < time(marshal(x)),因此锁定可能会更快。