Close() of Golang billion small details

@Golang The close() of billions of small details,
what you overlook, is often the origin of the bug

close() pre-knowledge

1. Cannot close() a channel that has been closed()

package main

func main(){
    
    
	ch := make(chan int)
	close(ch)
	close(ch)
	// output:
	// panic: close of closed channel
}

2. After the channel is closed(), it cannot be written (note that it will panic: send on closed channel), but it can be read. The reading rule is to read the cache value if there is a cache value, and read zero if there is no cache value. Note: v, ok := <-chChina okcannot determine when the channel is closed

package main

import "fmt"

func main() {
    
    
	ch := make(chan int,3)
	for i := 0; i < 3; i++ {
    
    
		ch <- i
	}
	close(ch)
	for i := 0; i < 5; i++ {
    
    
		v, ok := <-ch
		fmt.Println(v, ok)
	}
	fmt.Println("如果没有下一行就是写入失败被阻塞了啊")
	ch <- 1
	fmt.Println("我是下一行")
	/*
	output:
	0 true
	1 true
	2 true
	0 false
	0 false
	如果没有下一行就是写入失败被阻塞了啊
	panic: send on closed channel
	*/
}

Note:v, ok := <-ch China okdoes not necessarily determine when the channel is closed

package main

import "fmt"

func main() {
    
    
	ch := make(chan int, 3)
	for i := 1; i < 4; i++ {
    
    
		ch <- i
	}
	close(ch)
	for i := 0; i < 4; i++ {
    
    
		v, ok := <-ch
		fmt.Println(v,ok)
	}
	/*
	output
	1 true
	2 true 
	3 true 
	0 false
	*/
}

Why okis it unreliable to use the mode to determine whether the channel is closed?
As output, the cache memory in the channel in the value, even if the channel is closed, okthe value is still true, to remember 0and falseis one pair of Oh! When the channel is closed and there is no cache value, it okis false. When using the channel at the same time, it is best to close it when it is not needed. If all goroutineare blocked, it willpanic

Serve

The following code is provided by the brainstorming Go language group friends Tanhua month by month . He asked a question. All three coroutines have close(). Why is there no output?
panic: close of closed channelSee the comments for details.

package main

import (
   "fmt"
)

func main() {
    
    
   a := 0
   fn := func() int {
    
    
      a++
      return a
   }
   ch := make(chan int, 1)
   chh := make(chan int, 3)
   for i := 0; i < 3; i++ {
    
    
      go func(j int) {
    
    
         for {
    
    
            ch <- 1
            n := fn()
            if n > 100 {
    
    
            	// 当第一个协程进入这段代码区域时,chh最终会被关闭
            	// 剩下的两个协程因为chh被关闭,在写入按理来说应该会报panic: send on closed channel
            	// 然而并未出现,原因在于其实协程在ch <- 1 的位置被阻塞了,为何?
            	// ch容量为1,在第一个协程退出的时候并为将ch中的值取出,导致被阻塞
               chh <- 1
               close(chh)
               return
            }
            fmt.Println("go", j, n)
            <-ch
         }
      }(i)
   }
   for i := 0; i < 3; i++ {
    
    
   	// 那这样是不是代表这chh中只有一个值,是的!但是为何主进程没阻塞呢?
   	// 原因在于channle被关闭能读出0,所以这个循环在chh被关闭后马上就结束了
      <-chh
   }
}

Dessert

After solving the above problem month by month, Tan Hua also raised a question, how to use the channel to achieve safe exit? , In fact, the above scheme is just a prototype, just need to modify the code slightly. For the convenience of reading, I will reorganize the code while the basic disk of the above code remains unchanged.

func main() {
    
    
	data := make(chan int, 100) // 用来存储0-100
	code := make(chan int, 1)   // 相当于ch,写入code则有执行权
	count := make(chan int, 3)  // 相当于chh,用于统计

	for i := 0; i < 3; i++ {
    
    
		go func(code chan int, data <-chan int, count chan<- int) {
    
    
			for {
    
    
				code <- 1 // 获得执行权
				if v, ok := <-data; ok {
    
    
					fmt.Println(v)
					<-code //释放执行权
				} else {
    
    
					count <- 1 // 计数
					<- code //释放执行权
					return
				}
			}
		}(code, data, count)
	}

	go func(data chan<- int) {
    
    
		for i := 0; i < 101; i++ {
    
    
			data <- i
		}
		close(data)
	}(data)

	for i := 0; i < 3; {
    
    
		i = i + <-count // 统计
	}
}

In fact, this implementation is similar to sync.WaitGroup.

Guess you like

Origin blog.csdn.net/qq_17818281/article/details/115000706