我第一次在这里发帖,因为我在互联网上找不到干净的解决方案。
我的目标很简单,我需要创建 一个 后台操作 (goroutine 或进程或其他...)我可以 正确杀死 (不要留在后台)。
我尝试了很多事情,比如使用 chan 或 context。
但我永远找不到避免泄漏的正确方法。
这是一个例子:
package main
import (
"log"
"strconv"
"runtime"
"time"
"math/rand"
)
func main() {
log.Println("goroutines: " + strconv.Itoa(runtime.NumGoroutine()))
func1()
leak := ""
if runtime.NumGoroutine() > 1 {
leak = " there is one LEAK !!"
}
log.Println("goroutines: " + strconv.Itoa(runtime.NumGoroutine()) + leak)
}
func func1() {
done := make(chan struct{})
quit := make(chan struct{})
go func() {
log.Println("goroutines: " + strconv.Itoa(runtime.NumGoroutine()))
select {
case <-quit:
log.Println("USEFUL ???")
return
default:
func2()
done<-struct{}{}
}
}()
select {
case <-time.After(4 * time.Second):
quit<-struct{}{}
log.Println("TIMEOUT")
case <-done:
log.Println("NO TIMEOUT")
}
}
func func2() {
log.Println("JOB START")
rand.Seed(time.Now().UnixNano())
val := rand.Intn(10)
log.Println("JOB DURATION: " + strconv.Itoa(val))
time.Sleep(time.Duration(val) * time.Second) // fake a long process with an unknown duration
log.Println("JOB DONE")
}
在这个例子中,如果工作在 4 秒超时之前完成,一切都很好,goroutine 的最终数量将为 1,否则它将像我能找到的每个示例一样为 2。
但这只是一个例子,也许使用 goroutines 不可能,也许在 Go 中甚至不可能。
最佳答案
你的问题在这里:
quit := make(chan struct{})
go func() {
for {
select {
case <-quit:
log.Println("USEFUL ???")
return
default:
func2()
quit<-struct{}{}
return
}
}
}()
这个 goroutine 在 上发出信号无缓冲 channel 。这意味着当它到达
quit<-struct{}{}
,该发送将永远阻塞,因为它正在等待自己接收。不过,尚不完全清楚这是如何工作的。这里发生了一些奇怪的事情:quit<-struct{}{}
可以替换为 log.Println("USEFUL ???")
并且可以删除整个 for/select/channel 业务 case
中返回的select
, 所以把它放在一个循环中是没有意义的 - 没有任何场景可以让这个代码执行循环的第二次迭代 关于go - 管理后台操作(创建/杀死),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61952220/