Golang 入门资料+笔记

Go 踩过的坑之协程 参数不能过大

2021-02-21  本文已影响0人  五岁小孩

Go 踩过的坑之协程 参数不能过大

先知

新开goroutine的可用堆栈空间默认分配2k的内存
故传入的参数不宜过大,否则导致程序panic

问题重现

从mysql请求的切片数据,遍历后开启协程根据指定字段统计数据,此处采用了协程组的方式提高效率

代码如下:

//结构体
type RespStruct struct{
    struct01 //内嵌另外的结构体
    struct02 //内嵌另外的结构体
}
func StatisticData(){
    var respData []RespStruct
    var wg sync.WaitGroup
    //1.从mysql查询数据,封装到respData ,代码省略
    //2.循环respData并且开启协程组,添加协程
    for i, d := range respData {
        wg.Add(1)
         go func(req ProduceOrderProcessQueryRespParam) {
            defer func() {
                wg.Done()
            }()
            //打印参数
             fmt.Println(req)
            return
        }(d)
    }
    wg.wait()
    fmt.Println("end.....")
}

输出:

fatal error: newproc: function arguments too large for new goroutine

原因:

由于结构体嵌结构体,变成新的比较大的结构体d。那么在启动新协程的时候,又因为是值传递,新copy了一份d的副本,导致参数超过了新goroutine的可用堆栈空间。 goroutine默认分配2k的内存

解决:

  • 1.改为指针类型传递
  • 2.减少传递参数的大小,只传入需要使用的参数
  • 3.去除协程

拓展:

将协程 的匿名函数修改为函数调用方式;代码修改如下

//结构体
type RespStruct struct{
    struct01 //内嵌另外的结构体
    struct02 //内嵌另外的结构体
}
func StatisticData(){
    var respData []RespStruct
    //var wg sync.WaitGroup
    //1.从mysql查询数据,封装到respData ,代码省略
    //2.循环respData并且开启协程组,添加协程
    for i, d := range respData {
        //wg.Add(1)
        go StatistisData02(d)
    }
   // wg.wait()
    fmt.Println("end.....")
}
func StatistisData02(req ProduceOrderProcessQueryRespParam) {
            defer func() {
                wg.Done()
            }()
            //打印参数
             fmt.Println(req)
            return
}

输出:

fatal error: newproc: function arguments too large for new goroutine

仍然不行

上一篇下一篇

猜你喜欢

热点阅读