Multithreading problem

When multiple coroutines access the same resource, there will be resource competition, so how to ensure the safety of concurrent threads, in this case, channel can be generated

Why channel is needed

  1. The previous use of global variable lock synchronization for goroutine communication was not perfect
  2. It is difficult to determine how long the main thread will wait for all the goroutines to complete, so we set 10 seconds here, just to estimate
  3. If the main thread sleeps for a long time, the wait time will increase. If the wait time is short, the Goroutine may still be working, which will also be destroyed when the main thread exits
  4. Global variables lock synchronization to achieve communication, and does not use multiple coroutines to read and write global variables

The channel is introduced

It’s essentially queue, fifO, thread safe, multiple Goroutines accessing channels thread safe

use

  • Channel is a reference type
  • It must be initialized before it can be used.
  • Pipes have type

Panic: Send on Closed Channel can be used to close a channel, but data can continue to be read

For-range traverses the pipe, deadlock if the pipe is not closed, deadlock if the pipe is closed. It exits the loop normally

A deadlock occurs if it is not closed

var intCh chan int
intCh = make(chan int.3)
intCh <- 10
intCh <- 11
intCh <- 12

for i := rangeIntCh {fmt.println (I)}10
11
12
fatal error: all goroutines are asleep - deadlock!
Copy the code

Close. Exit normally

var intCh chan int
intCh = make(chan int.3)
intCh <- 10
intCh <- 11
intCh <- 12
close(intCh)
for i := rangeIntCh {fmt.println (I)}10
11
12
Copy the code

At the same time, speaking, reading and writing


var (
   ch    = make(chan int.50)
   flag  = true
)

func main(a) {
   go write()
   go read()

   for flag {
   }
}

func read(a) {
   for {
      a, ok := <-ch
      if ok {
         fmt.Println(a)
      } else {
         break}}}func write(a) {
   for i := 0; i < 50; i++ {
      ch <- i
      fmt.Println("write", i)
      time.Sleep(time.Second)
   }
   close(ch)
   flag = false} Output: Write0
0
write 1
1
write 2
2
write 3
3
write 4
4
write 5
5
write 6
6
Copy the code

As you can see, write and read are alternating. When the pipe finishes writing data and closes the pipe, flag is false and the main thread exits

Unbuffered piping

Func recv(c chan int) {ret := <-c FMT.Println(" ", Ret)} func main() {ch := make(chan int) go recv(ch)Copy the code

If you create an unbuffered pipe and send data to the pipe, you must have a receive to send. Otherwise a deadlock will occur

A one-way passage

Restrict a channel in a function to accept or send only

func counter(out chan<- int) {
	for i := 0; i < 100; i++ {
		out <- i
	}
	close(out)
}

func squarer(out chan<- int, in <-chan int) {
	for i := range in {
		out <- i * i
	}
	close(out)
}
func printer(in <-chan int) {
	for i := range in {
		fmt.Println(i)
	}
}

func main(a) {
	ch1 := make(chan int)
	ch2 := make(chan int)
	go counter(ch1)
	go squarer(ch2, ch1)
	printer(ch2)
}
Copy the code
  • chan<- intIs a write-only one-way channel (only int can be written to it) that can be sent but cannot be received.
  • <-chan intIs a read-only one-way channel (from which only int values can be read) that can be received but cannot be sent.

A two-way channel can be converted to a one-way channel in function argument passing and any assignment, but not the other way around

The SELECT mode never turns off pipe fetching data

When there is data in the pipe, case will be used. After all data is fetched, default will be used

func main(a) {
   intChan := make(chan int.10)
   for i := 0; i < 10; i++ {
      intChan <- i
   }
   strChan := make(chan string.5)
   for i := 0; i < 5; i++ {
      strChan <- "hello" + string(rune(i))
   }

label:
   for {
      select {
      case v := <-intChan:
         fmt.Println(v)
      case s := <-strChan:
         fmt.Println(s)
      default:
         break label
      }
   }
}
Copy the code

Considerations when using Goroutine

If panic occurs, the entire application will crash, so you can use defer plus the anonymous function

func test(a)  {
   defer func(a) {
      if r := recover(a); r ! =nil {
         fmt.Println("Test misjudged me")}} ()var myMap map[int]string
   myMap[0] = "111"
}
Copy the code