2017-01-12 52 views
5

我有以下示例代碼。我想保持4個goroutines始終運行。他們有恐慌的可能性。在恐慌的情況下,我恢復了重新啓動goroutine的地方。Golang,正確的方式來重新啓動一個恐慌的例程

我實施的方式的工作,但我不知道是否正確和正確的方式來做到這一點。任何想法

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) 
} 

回答

1

哦,我不是說,下面的比你的方式更正確。這只是另一種方式。

創建另一個函數,將其稱爲printerRecover或類似的東西,並在那裏做延遲/恢復。然後在printer只是呼籲printerRecover循環。加入函數返回值來檢查你是否需要goroutine由於某種原因退出。

1

Zan Lynx的回答,我想分享另一種方式來做到這一點(雖然它非常類似於OP的方式)。我使用了一個額外的緩衝頻道ch。當goroutine發生混亂時,goroutine內部的恢復功能將其身份i發送到ch。在main()的底部的for循環中,它檢測哪個goroutine處於恐慌狀態,並通過接收ch的值來檢測是否重新啓動。

Run in Go Playground

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

可以提取功能的恢復邏輯,如:

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) }) 
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的產卵量非常小,運行時間對於平衡負載來說非常聰明。當然,你必須以任何方式恢復。這是我個人的看法。

+0

我試過這種方法,它只是不斷添加和添加。你如何限制goroutines的數量?它產卵goroutines這是主要問題 – Sakib

+0

@Sakib你可以做這樣的事情 func main(){ ... for i:= 0;我