我有以下示例代码。我想保持4个goroutines一直在运行。他们有恐慌的可能。在恐慌的情况下,我有一个恢复,我重新启动goroutine。
我实施的方式有效,但我不确定它是否是正确和正确的方法。任何想法
package main
import (
"fmt"
"time"
)
var gVar string
var pCount int
func pinger(c chan int) {
for i := 0; ; i++ {
fmt.Println("adding ", i)
c <- i
}
}
func printer(id int, c chan int) {
defer func() {
if err := recover(); err != nil {
fmt.Println("HERE", id)
fmt.Println(err)
pCount++
if pCount == 5 {
panic("TOO MANY PANICS")
} else {
go printer(id, c)
}
}
}()
for {
msg := <-c
fmt.Println(id, "- ping", msg, gVar)
if msg%5 == 0 {
panic("PANIC")
}
time.Sleep(time.Second * 1)
}
}
func main() {
var c chan int = make(chan int, 2)
gVar = "Preflight"
pCount = 0
go pinger(c)
go printer(1, c)
go printer(2, c)
go printer(3, c)
go printer(4, c)
var input string
fmt.Scanln(&input)
}
答案 0 :(得分:8)
您可以在以下函数中提取恢复逻辑:
func recoverer(maxPanics, id int, f func()) {
defer func() {
if err := recover(); err != nil {
fmt.Println("HERE", id)
fmt.Println(err)
if maxPanics == 0 {
panic("TOO MANY PANICS")
} else {
go recoverer(maxPanics-1, id, f)
}
}
}()
f()
}
然后使用它:
go recoverer(5, 1, func() { printer(1, c) })
答案 1 :(得分:1)
哦,我不是说以下比你的方式更正确。这只是另一种方式。
创建另一个函数,将其称为printerRecover
或类似的函数,并在那里执行延迟/恢复。然后在printer
中循环调用printerRecover
。添加函数返回值以检查是否由于某种原因需要goroutine退出。
答案 2 :(得分:1)
就像Zan Lynx的答案一样,我想分享另一种方法(虽然它与OP的方式非常相似。)我使用了额外的缓冲通道ch
。当goroutine发生恐慌时,goroutine内部的恢复功能会将其身份i
发送给ch
。在main()
底部的for循环中,它会通过接收来自ch
的值来检测恐慌中的哪个goroutine以及是否重新启动。
package main
import (
"fmt"
"time"
)
func main() {
var pCount int
ch := make(chan int, 5)
f := func(i int) {
defer func() {
if err := recover(); err != nil {
ch <- i
}
}()
fmt.Printf("goroutine f(%v) started\n", i)
time.Sleep(1000 * time.Millisecond)
panic("goroutine in panic")
}
go f(1)
go f(2)
go f(3)
go f(4)
for {
i := <-ch
pCount++
if pCount >= 5 {
fmt.Println("Too many panics")
break
}
fmt.Printf("Detected goroutine f(%v) panic, will restart\n", i)
f(i)
}
}
答案 3 :(得分:0)
您实施的方式是正确的。对我来说,保持正好运行4个例程的方法看起来并没有多少go_way,要么处理例程的ID,要么延迟产生,这可能导致由于关闭导致不可预测的堆栈。我认为你不能以这种方式有效地平衡资源。你需要什么时候不喜欢简单的产卵工人
func main() {
...
go func(tasks chan int){ //multiplexer
for {
task = <-tasks //when needed
go printer(task) //just spawns handler
}
}(ch)
...
}
让运行时完成它的工作?这样就可以在stdlib监听器/服务器中完成这些操作,并且已知它们足够高效。 goroutines非常轻量级,并且运行时非常智能以平衡负载。当然你必须以任何一种方式恢复。这是我个人的看法。