channel (pipeline)-basic introduction
Why do we need channels? Previously, global variables were used to lock and synchronize to solve goroutine communication, but it was not perfect.
1) It is difficult to determine the time the main thread waits for all goroutines to complete. We set 10 seconds here, which is just an estimate.
2) If the main thread sleeps for a long time, the waiting time will be lengthened. If the waiting time is short, there may still be goroutine in the working state. At this time, It will be destroyed when the main thread exits
3) Communication is achieved through global variable lock synchronization, and does not use multiple coroutines to read and write global variables.
4) All the above analyzes are calling for a new communication mechanism channel
package main
import (
"fmt"
"sync"
"time"
)
var (
m = make(map[int]int, 10)
//声明一个全局的互斥锁 lock是一个全局的互斥锁
//sync是包 同步的意思 mutex是互斥的意思
lock sync.Mutex
)
// test函数就是计算n的阶乘
func test(n int) {
res := 1
for i := 1; i <= n; i++ {
res = res * i
}
//将计算结果放到map当中 加锁
lock.Lock()
m[n] = res
lock.Unlock()
}
func main() {
//这里开启多协程完成任务
for i := 1; i <= 20; i++ {
go test(i)
}
time.Sleep(time.Second * 10)
for k, v := range m {
fmt.Println(k, v)
}
}
Introduction to channel
1)Channle is essentially a data structure - a queue, the data is first in first out
2) Thread safety,When accessed by multiple goroutines, no It needs to be locked, which means that the channel itself is thread-safe (pipes are thread-safe. When you read the pipe, no matter how many coroutines are operating on the same pipe, you can use it with confidence and no errors will occur. These It is maintained by the compiler at the bottom level)
3) Channels have types. A string channel can only store string type data. (If you want to put int or float in the pipe, you can use the empty interface interface type)
Define/declare channel
var variable name chan data type
Example:
var intChan chan int (intChan用于存放int数据)
var mapChan chan map[int]string (mapChan用于存放map[int]string类型)
var perChan chan Person
var perChan2 chan *Person
illustrate:
1)channel is quotation type
2)The channel must be initialized before data can be written, that is, it can be used after make
3) Pipes are typed, intChan can only write integer int
channel initialization
Description: Use make to initialize
var intChan chan int
intChan =make(chan int,10)
Write (store) data to the channel
var intChan chan int
intChan =make(chan int,10)
num =999
intChan<-10
intChan<-num
If the channel is passed to another function, the same pipe is operated in this function because it is a reference type.
package main
import "fmt"
func main() {
var intChan chan int
//创建可以存放3个int类型的管道
intChan = make(chan int, 3)
//看看intChan是什么
fmt.Printf("initChan的值为=%v\n initChan本身地址为%p\n", intChan, &intChan)
//向管道写入数据
intChan <- 1
num := 2
intChan <- num
//当给管道写入数据的时候,不能超过其容量
//看看管道的长度和cap
fmt.Println("长度:", len(intChan), "容量:", cap(intChan))
num1 := <-intChan
fmt.Println("取出来的第一个数据是:", num1)
fmt.Println("取出之后的长度:", len(intChan), "取出之后的容量:", cap(intChan))
//在没有使用协程的情况下,如果我们的管道数据已经全部取出,再取就会报告deadlock
}
initChan的值为=0xc00007a080
initChan本身地址为0xc00000a028
长度: 2 容量: 3
取出来的第一个数据是: 1
取出之后的长度: 1 取出之后的容量: 3
What kind of data should be put into the pipeline? This kind of data is flowing. It is put in on one side and read on the other side. In this way, a communication mechanism is formed. <-ch This acceptance method can also be used to throw away the data. The data is not wanted. This is also a way to obtain it, but it is not wanted.
Notes on channel usage
1.Only specified data types can be stored in the channel
2. Once the channel data is full, no more data can be added (a deadlock error will occur)
3. After taking out data from the channel, you can continue to put it in
4. Without the use of coroutines, if the channel data is fetched and then fetched again, a dead lock will be reported.
Read and write channel case
Many maps can be stored in the pipeline, and each map can have multiple key/value pairs. Here you need to make it before using map.
Pipes can also store structure instances.
Pointers can also be stored in pipes.
If we want to store mixed-type data in this pipe, we want to put both structures and strings. The data type here is the empty interface type interface{}, because any data type is considered to implement the empty interface.
Note: Remember to use type assertion when taking it out.
package main
import (
"fmt"
"reflect"
)
type Cat struct {
Name string
Age int
}
func main() {
allChan := make(chan interface{}, 3)
cat1 := Cat{
Name: "1",
Age: 10,
}
allChan <- "hello"
allChan <- 1
allChan <- cat1
<-allChan
<-allChan
newCat := <-allChan
fmt.Println(reflect.TypeOf(newCat))
fmt.Printf("%T\n %#v\n", newCat, newCat)
//fmt.Println(c.Name, c.Age) 这种写法是错误的,编译器通不过,使用类型断言即可
c := newCat.(Cat)
fmt.Println(c.Name, c.Age)
}
6) Store functions
ch := make(chan func(string) string, 10)
ch <- func(name string) string { //使用匿名函数
return "hello " + name
}