go-programming-tour-book / blog-service

《Go 语言编程之旅:一起用 Go 做项目》第二章:博客程序(HTTP Server)
Apache License 2.0
554 stars 187 forks source link

接口并发请求时报fatal error #33

Open javahanjun opened 2 years ago

javahanjun commented 2 years ago

测试方式: ab -c 10 -n 100 localhost:8000/debug/vars

测试结果:

fatal error: concurrent map read and map write

goroutine 139 [running]:
runtime.throw(0x4a46303, 0x21)
    /usr/local/go/src/runtime/panic.go:1116 +0x72 fp=0xc001b0c208 sp=0xc001b0c1d8 pc=0x4034962
runtime.mapaccess2(0x491bee0, 0xc0005cb080, 0xc001b0c288, 0x0, 0xc001a39601)
    /usr/local/go/src/runtime/map.go:469 +0x258 fp=0xc001b0c248 sp=0xc001b0c208 pc=0x400fbd8
github.com/go-playground/validator/v10.(*Validate).RegisterTranslation(0xc00008e4e0, 0x4a31dce, 0xc, 0x4bbb0e0, 0xc001a3bb60, 0xc001acc690, 0x4a6d278, 0x0, 0x0)
    /Users/hxj/godevspace/pkg/mod/github.com/go-playground/validator/v10@v10.2.0/validator_instance.go:261 +0xb0 fp=0xc001b0c2a8 sp=0xc001b0c248 pc=0x43ea6c0
github.com/go-playground/validator/v10/translations/zh.RegisterDefaultTranslations(0xc00008e4e0, 0x4bbb0e0, 0xc001a3bb60, 0x0, 0x62fdf00)
    /Users/hxj/godevspace/pkg/mod/github.com/go-playground/validator/v10@v10.2.0/translations/zh/zh.go:1321 +0x4f9 fp=0xc001b0d3b0 sp=0xc001b0c2a8 pc=0x480bfd9
github.com/go-programming-tour-book/blog-service/internal/middleware.Translations.func1(0xc000398000)
    /Users/hxj/Work/work_go/go-programming-tour-book/blog-service/internal/middleware/translations.go:30 +0x1ea fp=0xc001b0d458 sp=0xc001b0d3b0 pc=0x4816a8a
github.com/gin-gonic/gin.(*Context).Next(0xc000398000)
    /Users/hxj/godevspace/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 +0x3b fp=0xc001b0d478 sp=0xc001b0d458 pc=0x45e9f8b
github.com/go-programming-tour-book/blog-service/internal/middleware.ContextTimeout.func1(0xc000398000)
    /Users/hxj/Work/work_go/go-programming-tour-book/blog-service/internal/middleware/context_timeout.go:16 +0x14f fp=0xc001b0d4f8 sp=0xc001b0d478 pc=0x48161df
github.com/gin-gonic/gin.(*Context).Next(0xc000398000)
    /Users/hxj/godevspace/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 +0x3b fp=0xc001b0d518 sp=0xc001b0d4f8 pc=0x45e9f8b
github.com/go-programming-tour-book/blog-service/internal/middleware.RateLimiter.func1(0xc000398000)
    /Users/hxj/Work/work_go/go-programming-tour-book/blog-service/internal/middleware/limiter.go:23 +0x89 fp=0xc001b0d568 sp=0xc001b0d518 pc=0x4816449

修复方式: 去掉 translations.go中间件,将中间件中的函数内容放到main.go文件中,函数体:


// 在global包中定义全局变量

var Trans  ut.Translator

// InitTrans 初始化翻译器
func InitTrans(locale string) (err error) {
    // 修改gin框架中的Validator引擎属性,实现自定制
    if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
        zhT := zh.New() // 中文翻译器
        enT := en.New() // 英文翻译器
        // 第一个参数是备用(fallback)的语言环境
        // 后面的参数是应该支持的语言环境(支持多个)
        // uni := ut.New(zhT, zhT) 也是可以的
        uni := ut.New(enT, zhT, enT)

        // locale 通常取决于 http 请求头的 'Accept-Language'
        var ok bool
        // 也可以使用 uni.FindTranslator(...) 传入多个locale进行查找
        global.Trans, ok = uni.GetTranslator(locale)
        if !ok {
            return fmt.Errorf("uni.GetTranslator(%s) failed", locale)
        }
        // 注册翻译器
        switch locale {
        case "en":
            err = enTranslations.RegisterDefaultTranslations(v, global.Trans)
        case "zh":
            err = zhTranslations.RegisterDefaultTranslations(v, global.Trans)
        default:
            err = enTranslations.RegisterDefaultTranslations(v, global.Trans)
        }
        return
    }
    return
}

在main()函数中调用:

func main() {

        if err := InitTrans("zh"); err != nil {
        fmt.Printf("init trans failed, err:%v\n", err)
        return
    }
        ......
}

修改pkg/app/form.go文件中的

BindAndValid(){
// 直接用全局变量
for key, value := range verrs.Translate(global.Trans) {
 ....
}
}