dsm0688 2018-06-12 16:25
浏览 198
已采纳

结构中的线程,函数参数对于新的goroutine太大

I created this simple app to demonstrate the issue I was having.

package main

import (
    "fmt"
    "unsafe"
    "sync"
)

type loc_t struct {
    count       [9999]int64
    Counter     int64
}

func (l loc_t) rampUp (wg *sync.WaitGroup) {
    defer wg.Done()
    l.Counter += 1
}

func main() {
    wg := new(sync.WaitGroup)
    loc := loc_t{}

    fmt.Println(unsafe.Sizeof(loc))
    wg.Add(1)
    go loc.rampUp(wg)
    wg.Wait()
    fmt.Println(loc.Counter)
}

If I run the above I will get a fatal error: newproc: function arguments too large for new goroutine runtime stack: runtime: unexpected return pc for runtime.systemstack called from 0x0

Now the reason for that is the 2k stack size when a go is used to spawn a background task. What's interesting is I'm only passing a pointer the called function. This issue happened to me in production, different struct obviously, everything was working for a year, and then all of sudden it started throwing this error.

  • 写回答

2条回答 默认 最新

  • duancheng8000 2018-06-12 16:37
    关注

    Method receivers are passed to method calls, just like any other parameter. So if the method has a non-pointer receiver, the whole struct in your case will be copied. The easiest solution would be to use a pointer receiver, if you can.

    If you must use a non-pointer receiver, then you can circumvent this by not launching the method call as the goroutine but another function, possibly a function literal:

    go func() {
        loc.rampUp(wg)
    }()
    

    If the loc variable may be modified concurrently (before the launched goroutine would get scheduled and copy it for the rampUp() method), you can create a copy of it manually and use that in the goroutine, like this:

    loc2 := loc
    wg.Add(1)
    go func() {
        loc2.rampUp(wg)
    }()
    

    These solutions work because launching the new goroutine does not require big initial stack, so the initial stack limit will not get in the way. And the stack size is dynamic, so after the launch it will grow as needed. Details can be read here: Does Go have an "infinite call stack" equivalent?

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置