2015-12-10 19 views
5

Bekleme grubunda zahmetli bir şekilde nasıl ele alınır?Çalışma zamanı hatası, waitgroup'dan çağrılan bir işlevden nasıl yakalanır?

Başka bir deyişle, aşağıdaki kod parçacığında, do() yöntemini çağıran gorourinlerin panik/ezmelerini nasıl yakalayabiliriz?

func do(){ 
    str := "abc" 
    fmt.Print(str[3]) 
    defer func() { 
     if err := recover(); err != nil { 
      fmt.Print(err) 
     } 
    }() 
} 

func main() { 
    var wg sync.WaitGroup 

    for i := 0; i < 1; i++ { 
     wg.Add(1) 
     go do() 
     defer func() { 
      wg.Done() 
      if err := recover(); err != nil { 
       fmt.Print(err) 
      } 
     }() 
    } 
    wg.Wait() 
    fmt.Println("This line should be printed after all those invocations fail.") 
} 

cevap

3

İlk olarak, en son yapmak yana, hatta ulaşılamayan gibi, fonksiyonun ilk satırı olmalıdır kurtarmak için ertelenmiş işlevi kayıt ettikleri satır/kod defer zaten panikler ve böylece önce ertelenmiş işlev, panik durumunu geri yükleyecektir.

Yani bu şekilde do() işlevini değiştirin:

func do() { 
    defer func() { 
     if err := recover(); err != nil { 
      fmt.Println("Restored:", err) 
     } 
    }() 
    str := "abc" 
    fmt.Print(str[3]) 
} 

İkincisi: Eğer sadece bir kez main() bitirir aday olacağını hangi ertelenmiş fonksiyonunda wg.Defer() dediğimiz gibi bu tek başına, kodunuzu çalışmasını sağlamaz - çünkü asla hangi main() numaranızda wg.Wait()'u arayın. Yani wg.Wait(), wg.Done() çağrılarını bekler, ancak wg.Done() çağrıları, wg.Wait() geri döndürene kadar çalıştırılmaz. Bu bir kilitlenme. Sen ertelenmiş işlevinde, do() işlevinden wg.Done() çağırmalıdır

, böyle bir şey:

var wg sync.WaitGroup 

func do() { 
    defer func() { 
     if err := recover(); err != nil { 
      fmt.Println(err) 
     } 
     wg.Done() 
    }() 
    str := "abc" 
    fmt.Print(str[3]) 
} 

func main() { 
    for i := 0; i < 1; i++ { 
     wg.Add(1) 
     go do() 
    } 
    wg.Wait() 
    fmt.Println("This line should be printed after all those invocations fail.") 
} 

Çıkış (Go Playground üzerinde denemek):

Restored: runtime error: index out of range 
This line should be printed after all those invocations fail. 

Bu tabii gerekiyordu wg değişkenini genel kapsamına taşıyın. Başka bir seçenek de argüman olarak do()'a geçmek olabilir. Bu şekilde gitmeye karar verirseniz, bir işaretçiyi WaitGroup'a iletmeniz gerektiğini unutmayın, yalnızca bir kopyanın geçirilmesi gerekir (WaitGroup bir struct türüdür) ve bir kopyanın kopyasını WaitGroup.Done() çağırmak, orijinal üzerinde etkili olmayacaktır. WaitGroupdo() geçmesiyle birlikte

:

func do(wg *sync.WaitGroup) { 
    defer func() { 
     if err := recover(); err != nil { 
      fmt.Println("Restored:", err) 
     } 
     wg.Done() 
    }() 
    str := "abc" 
    fmt.Print(str[3]) 
} 

func main() { 
    var wg sync.WaitGroup 
    for i := 0; i < 1; i++ { 
     wg.Add(1) 
     go do(&wg) 
    } 
    wg.Wait() 
    fmt.Println("This line should be printed after all those invocations fail.") 
} 

Çıktı aynıdır. Bu varyantı Go Playground numaralı telefondan deneyin.

0

@icza uygun WaitGroup kullanmak ve fonksiyonları Wait ve

Done Ben WaitGroup basitlik gibi nasıl açıklayan harika bir iş yaptı. Ancak, referansı goroutine iletmemiz gerektiği için sevmiyorum çünkü bu, eşzamanlılık mantığının iş mantığınızla karıştırılacağı anlamına gelir.

yüzden benim için bu sorunu çözmek için bu jenerik fonksiyonu ile geldi:

Yani örnek bu şekilde çözülebilir
// Parallelize parallelizes the function calls 
func Parallelize(functions ...func()) { 
    var waitGroup sync.WaitGroup 
    waitGroup.Add(len(functions)) 

    defer waitGroup.Wait() 

    for _, function := range functions { 
     go func(copy func()) { 
      defer waitGroup.Done() 
      copy() 
     }(function) 
    } 
} 

:

func do() { 
    defer func() { 
     if err := recover(); err != nil { 
      fmt.Println(err) 
     } 
    }() 

    str := "abc" 
    fmt.Print(str[3]) 
} 

func main() { 
    Parallelize(do, do, do) 

    fmt.Println("This line should be printed after all those invocations fail.") 
} 

Kullanmaya istiyorsanız, Burada bulabilirsiniz https://github.com/shomali11/util

İlgili konular