2 回答
TA贡献1828条经验 获得超3个赞
简单地使用https://eli.thegreenplace.net/2019/on-concurrency-in-go-http-servers/中的示例可以构建一个简单的示例,表明它并不安全。
使用一个简单的程序,如:
package main
import (
"net/http"
)
func main() {
counters := map[string]int{}
name := "test"
counters[name] = 0
http.HandleFunc("/test", func(w http.ResponseWriter, req *http.Request) {
counters[name]++
})
http.ListenAndServe(":8000", nil)
}
并刺激使用:
ab -n 20000 -c 200 "127.0.0.1:8000/test"
产生异常,如:
goroutine 158 [running]:
runtime.throw({0x64d95a, 0x81faa0})
/usr/local/go/src/runtime/panic.go:1198 +0x71 fp=0xc000384980 sp=0xc000384950 pc=0x4348f1
runtime.mapaccess2_faststr(0x697360, 0xc0003a4ba0, {0x644851, 0x4})
/usr/local/go/src/runtime/map_faststr.go:116 +0x3d4 fp=0xc0003849e8 sp=0xc000384980 pc=0x413d34
main.main.func1({0x69bf00, 0xc0003a4b60}, 0x0)
/home/test/gohttp/main.go:13 +0x46 fp=0xc000384a48 sp=0xc0003849e8 pc=0x5eba86
net/http.HandlerFunc.ServeHTTP(0x0, {0x69bf00, 0xc0003a4b60}, 0x0)
TA贡献1775条经验 获得超8个赞
如果您只阅读,那是安全的。
如果你需要写,你需要一些方法来做到“线程安全”
第一个想法是使用 sync.Mutex 来保护对地图的访问
然而,这可能成为瓶颈,因为您可能有多个并行请求,但每次只能写入一个。我们谈论的是纳秒……
第二种方法可以使用读/写互斥锁来控制读写。许多 goroutines 可以读取,但每次只有一个可以写入。
包同步和同步/原子还有其他选项。
还有一种额外的方法需要考虑:如果你只需要写入这个地图,你可以考虑使用缓冲通道发送一个键/值结构,以便在单个 goroutine 中使用(负责将它存储到地图中)
如您所见,如果对您的应用程序有意义,这种方法有很多优点。
您甚至可以使用通道通过回调来安全读/写,但这是另一回事了。
如果您有疑问,请编写单元测试并使用竞争条件检测器
- 2 回答
- 0 关注
- 103 浏览
添加回答
举报