官术网_书友最值得收藏!

Single goroutine halting the complete program

We know that goroutines run across multiple threads and multiple cores. So what happens when we have a panic in one of the threads? Here is an example that would let us simulate such a situation. We will create a lot of similar goroutines, whose sole purpose is to take a number and divide it by itself after subtracting 10 from the denominator. This will work fine for the majority of cases, except when the number is 10. The following code implements the described functionality:

package main 
 
import ( 
    "fmt" 
    "sync" 
) 
 
func simpleFunc(index int, wg *sync.WaitGroup) { 
    // This line should fail with Divide By Zero when index = 10 
    fmt.Println("Attempting x/(x-10) where x = ", index, " answer is : ", index/(index-10)) 
    wg.Done() 
} 
 
func main() { 
    var wg sync.WaitGroup 
    wg.Add(40) 
    for i := 0; i < 40; i += 1 { 
        go func(j int) { 
            simpleFunc(j, &wg) 
        }(i) 
    } 
 
    wg.Wait() 
}

The output of the previous code can be as follows:

Attempting x/(x-10) where x =  39  answer is :  1
Attempting x/(x-10) where x = 20 answer is : 2...
Attempting x/(x-10) where x = 37 answer is : 1
Attempting x/(x-10) where x = 11 answer is : 11
panic: runtime error: integer divide by zerogoroutine 15 [running]:main.simpleFunc(0xa, 0xc42000e280)
...
exit status 2

Essentially, a lot of goroutines were put in the runqueue, and upon being executed in random order, their outputs were printed to the console. However, as soon as the goroutine with index == 10 was executed, it raised a panic which was not handled by the function, and this resulted in the complete program halting and exiting with status code 2. This shows that even a single error or panic that hasn't been handled will halt the complete program!

However, it wouldn't make sense to crash the program because we faced a panic that we might have been able to handle graciously. Go allows us to recover from a panic with an appropriately named function called recover. Let's look at how to use recover in the previous code example:

package main 
 
import ( 
    "fmt" 
    "sync" 
) 
 
func simpleFunc(index int, wg *sync.WaitGroup) { 
    // functions with defer keyword are executed at the end of the function 
    // regardless of whether the function was executed successfully or not. 
    defer func() { 
        if r := recover(); r != nil { 
            fmt.Println("Recovered from", r) 
        } 
    }() 
 
    // We have changed the order of when wg.Done is called because 
    // we should call upon wg.Done even if the following line fails. 
    // Whether a defer function exists or not is dependent on whether it is registered 
    // before or after the failing line of code. 
    defer wg.Done() 
    // This line should fail with Divide By Zero when index = 10 
    fmt.Println("Attempting x/(x-10) where x = ", index, " answer is : ", index/(index-10)) 
} 
 
func main() { 
    var wg sync.WaitGroup 
    wg.Add(40) 
    for i := 0; i < 40; i += 1 { 
        go func(j int) { 
            simpleFunc(j, &wg) 
        }(i) 
    } 
 
    wg.Wait() 
}

The output for the preceding code can be as follows:

Attempting x/(x-10) where x =  39  answer is :  1                                     Attempting x/(x-10) where x =  14  answer is :  3                                     Recovered from runtime error: integer divide by zero                                  Attempting x/(x-10) where x =  3  answer is :  0                                      ...Attempting x/(x-10) where x =  29  answer is :  1                                     Attempting x/(x-10) where x =  9  answer is :  -9 
主站蜘蛛池模板: 行唐县| 内乡县| 沈阳市| 宁南县| 谢通门县| 枣强县| 广河县| 西华县| 万宁市| 宝丰县| 育儿| 玛多县| 海宁市| 渭源县| 青岛市| 河北省| 垫江县| 吴旗县| 长兴县| 应城市| 苏尼特左旗| 黄龙县| 沭阳县| 长武县| 山阴县| 海南省| 禄劝| 土默特左旗| 嘉峪关市| 峨边| 金乡县| 维西| 枣阳市| 庆阳市| 尉氏县| 遂平县| 鄢陵县| 黄浦区| 久治县| 波密县| 镇康县|