展开目录
http.ResponseWriter.Header().Set()不是线程安全的!
golang
X
陈尼玛的博客
记录开发生涯的踩坑经历,用时间来验证成长
加载中

用golang做项目有一段时间了,然而正式环境有时会遇到程序异常崩溃的问题。查看日志发现错误原因是:fatal error: concurrent map writes

详细错误日志如下:

fatal error: concurrent map writes

goroutine 9884217 [running]:
runtime.throw(0xb997f3, 0x15)
    /website/xdelve/plug/go/src/runtime/panic.go:596 +0x95 fp=0xc4204a9c48 sp=0xc4204a9c28
runtime.mapassign(0xb03220, 0xc420325470, 0xc4204a9d18, 0xc)
    /website/xdelve/plug/go/src/runtime/hashmap.go:499 +0x667 fp=0xc4204a9ce8 sp=0xc4204a9c48
net/textproto.MIMEHeader.Set(0xc420325470, 0xb91a44, 0xc, 0xb9b828, 0x18)
    /website/xdelve/plug/go/src/net/textproto/header.go:22 +0x71 fp=0xc4204a9d38 sp=0xc4204a9ce8
net/http.Header.Set(0xc420325470, 0xb91a44, 0xc, 0xb9b828, 0x18)
    /website/xdelve/plug/go/src/net/http/header.go:31 +0x53 fp=0xc4204a9d70 sp=0xc4204a9d38
treemonster/server.(*T_Response).SetHeader(0xc420325e90, 0xb91a44, 0xc, 0xb9b828, 0x18)
    /website/other/golang/src/treemonster/server/response.go:41 +0x69 fp=0xc4204a9da8 sp=0xc4204a9d70
treemonster/server.(*T_Response).JSONSuccess(0xc420325e90, 0xaa2f00, 0xc4201ae1a8, 0xaa2f00, 0xc4201ae1a8)
    /website/other/golang/src/treemonster/server/response.go:49 +0x61 fp=0xc4204a9de0 sp=0xc4204a9da8
_/website/other/golang/go/app/controller.(*ApiController).Proxy.func1(0xc4201ae0b0, 0xc4201ae040)
    /website/other/golang/go/app/controller/Api.go:31 +0x3a8 fp=0xc4204a9f10 sp=0xc4204a9de0
treemonster/js.(*T_Promise).getnew.func2.1()
    /website/other/golang/src/treemonster/js/Promise.go:102 +0x91 fp=0xc4204a9f50 sp=0xc4204a9f10
treemonster/js.Try(0xc42037a7b0, 0xc42037a7a8, 0x1, 0x1)
    /website/other/golang/src/treemonster/js/Try.go:11 +0x61 fp=0xc4204a9f88 sp=0xc4204a9f50
treemonster/js.(*T_Promise).getnew.func2()
    /website/other/golang/src/treemonster/js/Promise.go:103 +0x89 fp=0xc4204a9fe0 sp=0xc4204a9f88
runtime.goexit()
    /website/xdelve/plug/go/src/runtime/asm_amd64.s:2197 +0x1 fp=0xc4204a9fe8 sp=0xc4204a9fe0
created by treemonster/js.SetImmediate
    /website/other/golang/src/treemonster/js/Timer.go:56 +0x33

......

concurrent map writes实际原因是多个线程同时操作了map类型的变量。

通过日志信息我确定了出错的代码为:

  r.Raw.Header().Set(key, value)

这里的r.Raw返回的是http.ResponseWriterHeader() 即 http.Header。由于Set方法是官方代码的,因此我此前从未考虑过可能会出现线程安全的错误。但现在必须要确认其逻辑是否真的有问题。

我查看了其定义出的代码:

https://golang.org/src/net/http/header.go?s=349:380#L9

func (h Header) Set(key, value string) {
      textproto.MIMEHeader(h).Set(key, value)
  }

https://golang.org/src/net/textproto/header.go?s=657:699#L11

func (h MIMEHeader) Set(key, value string) {
      h[CanonicalMIMEHeaderKey(key)] = []string{value}
  }

结果上看到确实是直接写这个map的,没有加锁。Fuck。。。。

确认原因之后我很无奈,但只能自己做一个读写锁来处理,希望以后官方代码能修复这个问题吧。

相关文档

  1. 感谢beego陪伴我度过那不靠谱的半年

  2. golang 实现mysql Quote方法

  3. golang 限制goroutine并行个数

  4. golang 解压zip文件

  5. gb2312字符串转utf-8

  6. otto踩坑:substr()遇到utf8出错

  7. otto踩坑:vm.Interrupt导致goroutine无限增加

  8. 利用golang的反射实现类似js中的apply方法

随便看看

  1. cnpm 立即同步

  2. react项目webpack打包时拆分异步加载的文件

  3. 华为等国产手机rem宽度超过实际宽度

  4. word文件命令行打印

  5. curl用法

  6. SSL certificate problem: self signed certificate in certificate chain

  7. 树莓派实现用pi用户自动登录

  8. python 用摄像头拍照并写入文件

  9. 搜索命令整理

  10. nodejs俄罗斯方块

  11. dd备份/还原

  12. webpack使用外部资源

  13. putty使用http代理连接服务器

  14. mongodb2.4 添加用户

  15. mac搜索局域网内的主机

  16. bootstrap modal弹框导致ie无法获取焦点

  17. html表格导出csv文件并下载

畅言模块加载中