【发布时间】:2021-02-27 03:55:18
【问题描述】:
我怀疑我所有生成的 goroutine 是否在完成分配的工作后都死掉了。 我必须进行两次 HTTP 调用(总是),但基于一个标志,读取其中任何一个的响应。 到目前为止我所做的是 ->
var result error
resultChannel := make(chan error)
var wg sync.WaitGroup
wg.Add(1) // only adding 1, as I don't need to wait for other to complete.
go func() {
_, err := // HTTP call ONE
if flagIsTrue {
defer wg.Done()
resultChannel <- err
}
}()
go func() {
_, err := // HTTP call TWO
if !flagIsTrue {
defer wg.Done()
resultChannel <- err
}
}()
go func() {
wg.Wait()
close(resultChannel)
}()
for err := range resultChannel {
result = err
}
因此,我将等待相应的呼叫,并只听它的响应。这工作得很好,但是由于应用程序部署在服务器上,我猜主 goroutine 不会死(此后杀死其他 goroutine),我主要关心的是其他可忽略的线程是否会死HTTP 调用的响应(afaik,我们需要告诉 go 一个 goroutine 需要死掉)。 我的担忧:
- 假设(对我来说确实如此)主线程在执行这些调用之一后不会终止。
- 可忽略(响应是,但必须触发 API 调用)线程会死吗?
- 我是否应该使用选择案例来处理这个问题,如果是,那么如何处理(欢迎其他建议)?
【问题讨论】:
-
您的示例没有显示
flagIsTrue的来源或设置方式,这对于您的示例是否正常至关重要。一般来说,在通道上发送的 goroutine 也应该负责关闭它。 -
@super 该标志是在生成 goroutine 之前设置的。另外,通道要关闭了,我担心goroutine。
-
如果标志从未改变,这应该是安全的,因为只有一个 goroutine 写入结果通道。然而,它确实提出了一个问题,为什么你有一个等待组。为什么不简单地在 resultchannel 上接收一个值并继续前进?
-
@super 我想我误解了并发的概念,你能解释一下为什么不写入通道会确保这是安全的。我的印象是 goroutine 仍然存在。对于后续点,您是否建议创建一个 goroutie,进行两个 API 调用,然后根据标志将响应写入通道。
-
当一个goroutine执行的函数结束时,这个goroutine就不再活着。因此,在您的示例中,如果 goroutine 不写入结果通道,它将简单地停止。另一方面,如果它尝试写入 resultChannel,它将阻塞并等待,直到有人在另一端接收到值,从而保持活动状态。但是尝试在关闭的通道上发送也会引起恐慌,因此根据经验,写入方应该负责关闭通道。
标签: go concurrency channel goroutine