2 回答
TA贡献1852条经验 获得超1个赞
原则上,通道的使用是确保同步访问结构数据的有效方法。我在您的方法中看到的问题是您的Run函数只执行一次读取然后返回。只要您Run每次都从同一个 goroutine调用,它可能会起作用,但有一种更简单的方法。
只有将所有 struct 访问限制在一个且仅一个 goroutine 中才能保证内存安全。我通常这样做的方法是创建一个在通道上循环的轮询例程。无限期地,或直到它被明确停止。
这是一个例子。我为每个支持的操作创建了单独的频道,主要是为了更清楚地说明正在发生的事情。您可以轻松地使用单个通道,如chan interface{},并打开接收到的消息类型以查看您应该执行哪种操作。这种设置非常松散地基于 Erlang 的消息传递概念。它需要大量的样板来设置,但不需要互斥锁。它是否高效和可扩展,只有通过测试才能发现。还要注意,它包含了大量的分配开销。
package main
import "fmt"
func main() {
t := NewT()
defer t.Close()
t.Set("foo", 123)
fmt.Println(t.Get("foo"))
t.Set("foo", 321)
fmt.Println(t.Get("foo"))
t.Set("bar", 456)
fmt.Println(t.Get("bar"))
}
type T struct {
get chan getRequest
set chan setRequest
quit chan struct{}
data map[string]int
}
func NewT() *T {
t := &T{
data: make(map[string]int),
get: make(chan getRequest),
set: make(chan setRequest),
quit: make(chan struct{}, 1),
}
// Fire up the poll routine.
go t.poll()
return t
}
func (t *T) Get(key string) int {
ret := make(chan int, 1)
t.get <- getRequest{
Key: key,
Value: ret,
}
return <-ret
}
func (t *T) Set(key string, value int) {
t.set <- setRequest{
Key: key,
Value: value,
}
}
func (t *T) Close() { t.quit <- struct{}{} }
// poll loops indefinitely and reads from T's channels to do
// whatever is necessary. Keeping it all in this single routine,
// ensures all struct modifications are preformed atomically.
func (t *T) poll() {
for {
select {
case <-t.quit:
return
case req := <-t.get:
req.Value <- t.data[req.Key]
case req := <-t.set:
t.data[req.Key] = req.Value
}
}
}
type getRequest struct {
Key string
Value chan int
}
type setRequest struct {
Key string
Value int
}
- 2 回答
- 0 关注
- 177 浏览
添加回答
举报