在他对这个问题的回答中: Golang for Windows的不稳定行为? user @distributed建议锁定/同步对并发goroutines上的共享变量的访问.
我怎样才能做到这一点?
更多关于这个问题:
我得到views了同时在几个goroutine 上运行的代码(带有闭包的返回函数):
func makeHomeHandler() func(c *http.Conn, r *http.Request) {
views := 1
return func(c *http.Conn, r *http.Request) {
fmt.Fprintf(c, "Counting %s, %d so far.", r.URL.Path[1:], views)
views++
}
}
Run Code Online (Sandbox Code Playgroud)
看起来IO函数占用了它的时间,因此我得到了这种输出:
Counting monkeys, 5 so far.
Counting monkeys, 5 so far.
Counting monkeys, 5 so far.
Counting monkeys, 8 so far.
Counting monkeys, 8 so far.
Counting monkeys, 8 so far.
Counting monkeys, 11 so far.
Run Code Online (Sandbox Code Playgroud)
它增加很好,但是当它被打印时,我可以看到操作打印+递增根本不是原子的.
如果我将其更改为:
func makeHomeHandler() func(c *http.Conn, r *http.Request) {
views := 0
return func(c *http.Conn, r *http.Request) {
views++
// I can only hope that other goroutine does not increment the counter
// at this point, i.e., right after the previous line and before the
// next one are executed!
views_now := views
fmt.Fprintf(c, "Counting %s, %d so far.", r.URL.Path[1:], views_now)
}
}
Run Code Online (Sandbox Code Playgroud)
它似乎工作正常,但我不完全确定它最终是否会失败......
rog*_*rog 23
如果您想要一个同步计数器,那么使用sync.Mutex是规范的解决方案.同步/原子包只应用于低级别的东西,或者当您测量到严重的性能问题时.
type Counter struct {
mu sync.Mutex
x int64
}
func (c *Counter) Add(x int64) {
c.mu.Lock()
c.x += x
c.mu.Unlock()
}
func (c *Counter) Value() (x int64) {
c.mu.Lock()
x = c.x
c.mu.Unlock()
return
}
func makeHomeHandler() func(c http.ResponseWriter, r *http.Request) {
var views Counter
return func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Counting %s, %d so far.", r.URL.Path[1:], views.Value())
views.Add(1)
}
}
Run Code Online (Sandbox Code Playgroud)
对于您的特定问题,我建议定义一个满足http.Handler接口的新类型,而不是返回一个闭包.这看起来也更简单:
type homeHandler struct {
mu sync.Mutex
views int64
}
func (h *homeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.mu.Lock()
defer h.mu.Unlock()
fmt.Fprintf(w, "Counting %s, %d so far.", r.URL.Path[1:], h.views)
h.views++
}
func init() {
http.Handle("/", new(homeHandler))
}
Run Code Online (Sandbox Code Playgroud)
Rey*_*les 10
的同步包有一些同步原语.根据问题,您可以使用RWMutex或普通互斥锁.
如果您想要更具体的答案,请提供更多信息,了解它的用途.
编辑:在阅读链接的问题后,你可能正在寻找同步/原子,虽然Mutex也很好.
编辑2:我看到你用一个例子更新了你的帖子.这是使用sync/atomic的代码.
func makeHomeHandler() func(w http.ResponseWriter, r *http.Request) {
var views *uint64 = new(uint64)
atomic.StoreUint64(views, 0) // I don't think this is strictly necessary
return func(w http.ResponseWriter, r *http.Request) {
// Atomically add one to views and get the new value
// Perhaps you want to subtract one here
views_now := atomic.AddUint64(views, 1)
fmt.Fprintf(w, "Counting %s, %d so far.", r.URL.Path[1:], views_now)
}
}
Run Code Online (Sandbox Code Playgroud)
(注意:我没有测试过以上所以可能有拼写错误/脑筋流)我现在测试了它.