为了账号安全,请及时绑定邮箱和手机立即绑定

Go程序中goroutine的合理使用

Go程序中goroutine的合理使用

Go
一只萌萌小番薯 2021-12-07 10:31:27
我的程序有一个长时间运行的任务。我有一个jdIdList太大的列表- 最多1000000项目,所以下面的代码不起作用。有没有办法通过更好地使用 goroutine 来改进代码?似乎我有太多的 goroutine 正在运行,这使我的代码无法运行。运行的合理数量的 goroutine 是多少?var wg sync.WaitGroupwg.Add(len(jdIdList))c := make(chan string)// just think jdIdList as [0...1000000]for _, jdId := range jdIdList {    go func(jdId string) {        defer wg.Done()        for _, itemId := range itemIdList {            // following code is doing some computation which consumes much time(you can just replace them with time.Sleep(time.Second * 1)            cvVec, ok := cvVecMap[itemId]            if !ok {                continue            }            jdVec, ok := jdVecMap[jdId]            if !ok {                continue            }            // long time compute            _ = 0.3*computeDist(jdVec.JdPosVec, cvVec.CvPosVec) + 0.7*computeDist(jdVec.JdDescVec, cvVec.CvDescVec)        }        c <- fmt.Sprintf("done %s", jdId)    }(jdId)}go func() {    for resp := range c {        fmt.Println(resp)    }}()
查看完整描述

1 回答

?
繁华开满天机

TA贡献1816条经验 获得超4个赞

看起来您同时运行了太多东西,导致您的计算机内存不足。


这是您的代码版本,它使用有限数量的工作程序 goroutines 而不是您的示例中的一百万个 goroutines。由于一次只有几个 goroutine 运行,因此在系统开始交换之前,它们每个都有更多的可用内存。确保每个小计算所需的内存乘以并发 goroutines 的数量小于您系统中的内存,因此如果for jdId := range work循环内的代码需要少于 1GB 的内存,并且您有 4 个内核和至少 4 GB 的 RAM,设置clvl为4应该可以正常工作。


我还删除了等待组。代码仍然是正确的,但仅使用通道进行同步。通道上的 for 范围循环从该通道读取,直到它关闭。这就是我们在完成时告诉工作线程的方式。


https://play.golang.org/p/Sy3i77TJjA


runtime.GOMAXPROCS(runtime.NumCPU()) // not needed on go 1.5 or later

c := make(chan string)

work := make(chan int, 1) // increasing 1 to a higher number will probably increase performance

clvl := 4 // runtime.NumCPU() // simulating having 4 cores, use NumCPU otherwise

var wg sync.WaitGroup

wg.Add(clvl)

for i := 0; i < clvl; i++ {

    go func(i int) {

        for jdId := range work {

            time.Sleep(time.Millisecond * 100)

            c <- fmt.Sprintf("done %d", jdId)

        }

        wg.Done()

    }(i)

}


// give workers something to do

go func() { 

    for i := 0; i < 10; i++ {

        work <- i

    }


    close(work)

}()


// close output channel when all workers are done

go func() { 

    wg.Wait()

    close(c)

}()


count := 0

for resp := range c {

    fmt.Println(resp, count)

    count += 1

}

它在 go playground 上生成了这个输出,同时模拟了四个 CPU 内核。


done 1 0

done 0 1

done 3 2

done 2 3

done 5 4

done 4 5

done 7 6

done 6 7

done 9 8

done 8 9

请注意如何不保证排序。该jdId变量保存您想要的值。您应该始终使用gorace 检测器来测试您的并发程序。


另请注意,如果您使用的是 go 1.4 或更早版本并且尚未将 GOMAXPROCS 环境变量设置为内核数,则应该这样做,或者添加runtime.GOMAXPROCS(runtime.NumCPU())到程序的开头。


查看完整回答
反对 回复 2021-12-07
  • 1 回答
  • 0 关注
  • 257 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信