1. package main
    2. import "runtime"
    3. func main() {
    4. var ch = make(chan int, 100)
    5. go func() {
    6. for i := 0; i < 100; i++ {
    7. ch <- 1
    8. if i == 88 {
    9. runtime.GC()
    10. }
    11. }
    12. }()
    13. for {
    14. // the wrong part
    15. if len(ch) == 100 {
    16. sum := 0
    17. itemNum := len(ch)
    18. for i := 0; i < itemNum; i++ {
    19. sum += <-ch
    20. }
    21. if sum == itemNum {
    22. return
    23. }
    24. }
    25. }
    26. }

    image.png
    可以看到gcwaiting = 1
    以上代码,会导致程序hang住,因为在 for 循环中没有函数调用的话,编译器不会插入调度代码,所以这个执行 for 循环的 goroutine 没有办法被调出,而在循环期间碰到 gc,那么就会卡在 gcwaiting 阶段,并且整个进程永远 hang 死在这个循环上。并不再对外响应。

    稍做改动,在for中调用一个函数,这段程序将不会出现问题

    1. package main
    2. import (
    3. "fmt"
    4. "runtime"
    5. )
    6. func main() {
    7. var ch = make(chan int, 100)
    8. go func() {
    9. for i := 0; i < 100; i++ {
    10. ch <- 1
    11. if i == 88 {
    12. runtime.GC()
    13. }
    14. }
    15. }()
    16. for {
    17. fmt.Println("1--------------------------------1")
    18. if len(ch) == 100 {
    19. sum := 0
    20. itemNum := len(ch)
    21. for i := 0; i < itemNum; i++ {
    22. sum += <-ch
    23. }
    24. if sum == itemNum {
    25. return
    26. }
    27. }
    28. }
    29. }

    来一个http的例子:

    1. package main
    2. import (
    3. "fmt"
    4. "io"
    5. "log"
    6. "net/http"
    7. "runtime"
    8. "time"
    9. )
    10. func main() {
    11. runtime.GOMAXPROCS(runtime.NumCPU())
    12. go server()
    13. go printNum()
    14. var i = 1
    15. for {
    16. // will block here, and never go out
    17. i++
    18. }
    19. fmt.Println("for loop end")
    20. time.Sleep(time.Second * 3600)
    21. }
    22. func printNum() {
    23. i := 0
    24. for {
    25. i++
    26. }
    27. }
    28. func HelloServer(w http.ResponseWriter, req *http.Request) {
    29. io.WriteString(w, "hello, world!\n")
    30. }
    31. func server() {
    32. http.HandleFunc("/", HelloServer)
    33. err := http.ListenAndServe(":12345", nil)
    34. if err != nil {
    35. log.Fatal("ListenAndServe: ", err)
    36. }
    37. }

    在main中也是有一个for循环,运行几秒,在浏览器上输入url,第一次没问题,多试几次总有一次被卡住。导致代码hang住,原因也是上面提到过的