Golang:使用go协程时,WaitGroup可能会泄漏吗?

huangapple go评论77阅读模式
英文:

Golang: can WaitGroup leak with go-routines

问题

我计划实现一个go协程,并使用sync.WaitGroup来同步创建的go协程的结束。我使用go <function>来创建一个线程。代码如下:

func main() {
    var wg sync.WaitGroup
    for <some condition> {
        go myThread(wg)
        wg.Add(1)
    }
    wg.Wait()
}

func myThread(wg sync.WaitGroup) {
    defer wg.Done()
}

我之前使用过pthread_create,在某些情况下无法成功创建线程。在这种情况下,上述的go myThread(wg)是否有可能无法启动,并且/或者无法运行wg.Done()(如果其余的程序行为正确的话)?如果是这样,会报告什么错误,如何捕获错误?我担心在线程创建后使用wg.Add(1)可能会导致wg泄漏。(当然,也可以在函数内部使用wg.Add(1),但这会导致增量和主程序等待之间的其他竞争)。

我已经阅读了许多关于go协程的文档,没有提到调度或线程创建失败的情况。如果我创建数十亿个线程并耗尽了管理空间,会发生什么情况?go协程仍然能正常工作并且线程仍然会被创建吗?

英文:

I am planning to implement a go-routine and have a sync.WaitGroup to synchronize end of a created go-routine. I create a thread essentially using go &lt;function&gt;. So it is something like:

main() {
    var wg sync.WaitGroup
    for &lt;some condition&gt; {
        go myThread(wg)
        wg.Add(1)
    }
    wg.wait()
}

myThread(wg sync.WaitGroup) {
    defer wg.Done()
}

I have earlier worked with pthread_create which does fail to create a thread under some circumstances. With that context, is it possibly for the above go myThread(wg) to fail to start, and/or run wg.Done() if the rest of the routine behaves correctly? If so, what would be reported and how would the error be caught? My concern is a possible leak in wg due to wg.Add(1) following the thread creation. (Of course it may be possible to use wg.Add(1) within the function, but that leads to other races between the increment and the main program waiting).

I have read through numerous documentation of go-routines and there is no mention of a failure in scheduling or thread creation anywhere. What would be the case if I create billions of threads and exhaust bookkeeping space? Would the go-routine still work and threads still be created?

答案1

得分: 3

我不知道任何可能导致这种情况失败的方式,如果可能的话,它会导致恐慌(从而导致应用程序崩溃)。我从未见过这种情况发生,并且我知道有一些应用程序运行了数百万个goroutine的示例。唯一的限制因素是可用的内存来分配goroutine堆栈。

go foo() 不像 pthread_create。Goroutine 是由 Go 运行时处理的轻量级绿色线程,并且在操作系统线程上调度运行。启动一个 goroutine 不会启动一个新的操作系统线程。

英文:

I don't know of any possible way for this to fail, and if it is possible, it would result in a panic (and therefor application crash). I have never seen it happen, and I'm aware of examples of applications running millions of goroutines. The only limiting factor is available memory to allocate the goroutine stack.

go foo() is not like pthread_create. Goroutines are lightweight green threads handled by the Go runtime, and scheduled to run on OS threads. Starting a goroutine does not start a new OS thread.

答案2

得分: -1

你的代码问题不在于启动一个 goroutine(它本身不会“失败”),而是在于使用 sync.WaitGroup。你的代码有两个重大错误

  1. 在启动 goroutine 之前,你必须先执行 wg.Add(1),否则 Done() 可能会在 Add(1) 之前执行。

  2. 不能复制一个 sync.WaitGroup。在调用 myThread() 时,你的代码进行了复制。

这两个问题在 sync.WaitGroup 的官方文档和 https://golang.org/pkg/sync/#WaitGroup 给出的示例中都有解释。

英文:

The problem with your code is not in starting a goroutine (which cannot "fail" per se) or that like but in the use of sync.WaitGroup. Your code has two major bugs:

  1. You must do wg.Add(1) before launching the goroutine as otherwise the Done() could be executed before the Add(1).

  2. You must not copy a sync.WaitGroup. Your code makes a copy while calling myThread().

Both issues are explained in the official documentation to sync.WaitGroup and the given example in https://golang.org/pkg/sync/#WaitGroup

huangapple
  • 本文由 发表于 2017年8月22日 02:17:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/45803373.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定