这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
GO基础(三)
Channel
基本特性
- channel本身是一个队列,先进先出
- 线程安全,不需要加锁
- 本身是有类型的,string, int 等,如果要存多种类型,则定义interface类型
- channel是引用类型,必须make之后才能使用,一旦 make,它的容量就确定了,不会动态增加!!它和map,slice不一样
- 当写满时,不可以写,取空时,不可以取。
- 每次只能接收一个数据元素
无缓冲管道声明
无缓冲通道上的发送操作会阻塞,直到另一个goroutine在该通道上执行接收操作,这时值才能发送成功,两个goroutine将继续执行,因此,无缓冲通道也被称为同步通道。
通道实例 := make(chan 通道类型)
有缓冲管道的声明
通道实例 := make(chan 通道类型,缓冲大小)
阻塞条件
- 带缓冲通道被填满时,尝试再次发送数据时发生阻塞。
- 带缓冲通道为空时,尝试接收数据时发生阻塞。
channel的声明和使用
通道有发送(send)、接收(receive)和关闭(close)三种操作。发送和接收都使用<-符号。
通道创建后,就可以使用通道进行发送和接收操作。
创建一个可以放置三个int类型的管道
var ch chan int
ch = make(chan int,3)
向管道中写入数据
ch<-10
num :=100
ch<-num
阻塞式接收数据
data :=<-ch
非阻塞接收数据
data,ok :=<-ch
关闭和广播
关闭后的通道有以下特点:
- 对一个关闭的通道再发送值就会导致panic。
- 对一个关闭的通道进行接收会一直获取值直到通道为空。(如果通道中还有数据的话)
- 对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值。
- 关闭一个已经关闭的通道会导致panic。
ok为true代表正常接收,false代表通道关闭
所有channel的接收者都会在channel关闭时,立刻从阻塞等待中返回并且ok为false,被广播机制利用
close(channel)
if data,ok := <-channel;ok {
}
多渠道选择
select {
case ret :=<-retch1
t.Log(ret)
case ret :=<-retch2
t.Log(ret)
default:
t.Error("No one returned")
}
超时控制
select {
case ret :=<-retch1
t.Log(ret)
case <-time.After(time.Second *1)
t.Error("time out")
}
单例模式
package Test
import (
"fmt"
"sync"
"testing"
)
type Singleton struct {
}
var singleInstance *Singleton
var once sync.Once
func GetSingletonObj() *Singleton {
once.Do(func() {
fmt.Println("creat obj")
singleInstance = new(Singleton)
})
return singleInstance
}
func TestGetSing(t *testing.T) {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
obj := GetSingletonObj()
fmt.Println(obj)
wg.Done()
}()
}
wg.Wait()
}