我遇到一个问题,如果导出sync.Mutex
,我无法将结构保存为gob。如果我使互斥锁未被导出(通过不将其大写),一切似乎都有效。我很想知道为什么会这样,并且确保没有其他问题可以使用未被移植的sync.RWMutex
。
我发现Google上有几个针对package main
import (
"sync"
"encoding/gob"
"os"
"fmt"
)
func writeGob(filePath string, object interface{}) error {
file, err := os.Create(filePath)
defer file.Close()
if err != nil {
return err
}
encoder := gob.NewEncoder(file)
err = encoder.Encode(object)
return err
}
type Dog struct {
Name string
GobMux sync.Mutex
}
func main() {
d := &Dog{Name: "Fido"}
err := writeGob("./gob", d)
fmt.Printf("Error: %v\n", err)
}
的相关问题的点击,但没有一个真正解释为什么会发生这种情况。
{{1}}
输出:
错误:gob:type sync.Mutex没有导出的字段
答案 0 :(得分:0)
如果我不导出互斥锁(不使用大写字母),那么一切似乎都可以正常工作。我很好奇这是为什么。
与Cerise mentioned一样,有一个open issue,但是简而言之,如果您尝试对没有导出字段的结构(例如互斥锁)进行编码,通常会导致编程错误。
不过,有一些方法可以解决此特定问题。
您可以将互斥锁设为私有,并将锁定/解锁包装在公共函数中,而不是进入用于操作互斥锁的结构。例如
func (d *Dog) SetName(name string) {
d.GobMux.Lock()
d.Name = name
d.GobMux.Unlock()
}
您还可以包装类型并拉出互斥锁:
type Dog struct {
Name string
}
type DogWrapper struct {
Dog *Dog
GobMux sync.Mutex
}
如果您有许多小的结构,那么这将很麻烦,但是对于少量的更复杂的结构,这可能就可以了。
最后,解决此问题的“正确”方法是编写自己的GobEncode / Decode例程。 stdlib中有一些稀疏示例,例如time.GobEncode,但是通常这似乎需要大量工作。
...并确保对未导出的sync.Mutex进行咬刺没有其他问题。
Mutexes与Go运行时的进程内内存和调度程序紧密耦合。它们帮助Go运行时确定允许哪些goroutine读取或写入内存的特定部分,并帮助您确定何时计划安排这些goroutine(即,等待互斥体解锁的goroutine直到互斥体解锁后才会进行调度)
如果使用Gob将数据结构复制到另一个进程,则与发送gob的进程相比,接收方进程的运行时内部状态完全不同,因此互斥体无法进行逻辑传输。将互斥锁复制到另一个过程就像在火星上使用Earth GPS坐标一样。他们只是不匹配。
当我从料滴读回Dog对象时,无论将互斥量保存到料滴中时,无论该互斥量处于何种状态,该互斥量都似乎已解锁。我可以指望这种行为吗?
正如documentation for Mutex所述,“互斥锁的零值是未锁定的互斥锁。”是的,您可以依靠这种行为。
我认为,尽管gob出现在stdlib中,但它并没有引起太多关注,因为还有许多其他成熟的编码选项可用。如果gob不能满足您的需求,则可以使用许多其他选项-JSON,Cap'n Proto,net / rpc等,它们具有不同的特征,可能会更适合您。