2015-04-05 16 views
1

我創造,我運行功能同時裏面,我恐慌,恢復的例子:通恢復到上夠程golang

package main 

import "fmt" 

func main() { 
    // "main" recovery 
    defer func() { 
     if r := recover(); r != nil { 
      fmt.Println("main goroutine paniced:", r) 
     } 
    }() 

    // running function concurrently inside which I panic 
    chanStr := make(chan string) 
    go func() { 
     // this "internal" goroutin recovery 
     defer func() { 
      if r := recover(); r != nil { 
       fmt.Println("internal goroutine paniced:", r) 
      } 
      chanStr <- "hello world" 
     }() 
     // panicking and wanting recovery not only in "internal" recovery but in "main" recovery as well 
     panic("NOT main goroutine") 
    }() 
    // waiting for chan with "internal" goroutine panicking and recovery 
    str := <-chanStr 
    fmt.Println(str) 

    // panic("main") 
} 

它給輸出:

internal goroutine panicked: NOT main goroutine 
hello world 

是否可以更改我的代碼從「內部」恢復到「主要」?換句話說,我希望它寫下來到控制檯:

internal goroutine paniced: NOT main goroutine 
main goroutine paniced: main 
hello world 

我試圖在所有消除「內部」復甦FUNC實現這一點,但「主」恢復不恢復裏面的「內部」夠程恐慌在這案件。

Playground

更新

我試圖按照@ Momer的建議,並通過通道發送一個錯誤,並在主要的goroutine處理它,而不是試圖泡沫恐慌起來:

package main 

import (
    "errors" 
    "fmt" 
) 

func main() { 
    // "main" recovery 
    defer func() { 
     if r := recover(); r != nil { 
      fmt.Println("main goroutine paniced:", r) 
     } 
    }() 

    // running func concarantly inside which I panic 
    chanStr := make(chan string) 
    chanErr := make(chan error) 
    var err error 
    go func() { 
     // this "internal" goroutin recovery 
     defer func() { 
      if r := recover(); r != nil { 
       fmt.Println("internal goroutine paniced:", r) 
       switch t := r.(type) { 
       case string: 
        fmt.Println("err is string") 
        err = errors.New(t) 
       case error: 
        fmt.Println("err is error") 
        err = t 
       default: 
        fmt.Println("err is unknown") 
        err = errors.New("Unknown error") 
       } 

       chanErr <- err 
       chanStr <- "" 
      } 
     }() 
     // panicing and wanting recovery not only in "internal" recovery but in "main" recovery as well 
     panic("NOT main goroutine") 
     chanStr <- "hello world" 
     chanErr <- nil 

    }() 
    // waiting for chan with "internal" goroutin panicing and recovery 
    str := <-chanStr 
    err = <-chanErr 
    fmt.Println(str) 
    fmt.Println(err) 

    // panic("main") 
} 

它給錯誤

all goroutines are asleep - deadlock 

FUL l輸出:

go run /goPath/parentRecoverty2.go 
internal goroutine paniced: NOT main goroutine 
err is string 
fatal error: all goroutines are asleep - deadlock! 

goroutine 1 [chan receive]: 
main.main() 
    /goPath/parentRecoverty2.go:48 +0x1d4 

goroutine 5 [chan send]: 
main.func·002() 
    /goPath/parentRecoverty2.go:37 +0x407 
main.func·003() 
    /goPath/parentRecoverty2.go:42 +0x130 
created by main.main 
    /goPath/parentRecoverty2.go:46 +0x190 
exit status 2 

Update playground

+1

而不是試圖讓恐慌起來,爲什麼不通過通道發送錯誤,並在主要goroutine中處理它? – Momer 2015-04-05 13:52:26

+0

@Momer我試過了,但有錯誤'所有goroutines都睡着了 - 死鎖',請看我上面的更新。 – 2015-04-05 15:20:54

+0

第二次寫入(在恢復中)塊,因爲沒有人可以從通道讀取。你將要多次寫入它們,但只能讀一次。 – flx 2015-04-05 16:27:29

回答

1

在更新後的問題,一個線程是由chanStr讀取,而另一個線程被寫入chanErr封鎖封鎖。 切換寫入順序應解決死鎖問題。

defer func() { 
    if r := recover(); r != nil { 
     fmt.Println("internal goroutine paniced:", r) 
     switch t := r.(type) { 
     case string: 
      fmt.Println("err is string") 
      err = errors.New(t) 
     case error: 
      fmt.Println("err is error") 
      err = t 
     default: 
      fmt.Println("err is unknown") 
      err = errors.New("Unknown error") 
     } 
     chanStr <- "" 
     chanErr <- err 
    } 
} 
0

我在golang中把恐慌/恢復當作try/catch/final塊在java或C++中。

欲瞭解更多詳情,您可以訪問Handling panics (from Golang spec)

所以你可以傳遞一個恐慌方法的調用者。 一個簡單的代碼如下,希望它有幫助

注意:在函數Foo()中,我使用recover()來捕捉錯誤的事情,然後重新恐慌,以便稍後在外部調用方捕獲它。

package main 

import (
    "fmt" 
    "time" 
) 

func Foo() { 
    defer func() { 
     if x := recover(); x != nil { 
      fmt.Printf("Runtime panic: %v \n", x) 
      panic("Ah oh ... Panic in defer") 
     } 
    }() 
    panic("Panic in Foo() !") 
} 

func Game() { 
    defer func(){ 
     fmt.Println("Clean up in Game()") 
    }() 

    defer func() { 
     if x := recover(); x != nil { 
      fmt.Println("Catch recover panic !!! In Game()") 
     } 
    }() 
    Foo() 

} 

func main() { 

    defer func() { 
     fmt.Println("Program Quit ... ") 
    }() 

    fmt.Println("-----------Split-------------") 
    go Game() 
    time.Sleep(1 * time.Millisecond) 
    fmt.Println("-----------Split-------------") 
}