GO语言学习-接口interface
- 定义
- wait阻塞
- GOMAXPROCS
- 实现Local Storage
- Goexit
- 通道channel
- 单向通道
定义
并发(concurrency):逻辑上具备同时处理多个任务的能力。
并行(parallesim)不同于并发,物理上的同一时刻,相当于并发设计的理想执行模式。
在函数调用前添加 go关键字即可创建并发任务
a := 100
go func(x, y int){
//time.Sleep(time.Second)
println("go:",x,y) //立即计算并复制参数
}(a, counter())
a = a + 66
println("main:",a,counter())
输出:
main: 166 2
go: 100 1
wait阻塞
等待并发任务结束
1.通道channel
2.sync.WaitGroup
设定计数器,让goroutine在退出前递减,在归零时解除阻塞。
GOMAXPROCS
修改运行时的线程数量
runtime.GOMAXPROCS(),参数<1时,返回当前设置值,不作调整
实现Local Storage
goroutine没有局部存储,无法获取编号,返回值也会被抛弃,需自己写方法实现
不适用waitgroup时:
//var wg sync.WaitGroup
var gs [5]struct { //用于实现类似TLS的功能
id int //编号
result int //返回值
}
for i := 0;i < len(gs) ;i++ {
//wg.Add(1)
go func (id int){ //使用参数避免闭包求值延迟
//defer wg.Done()
gs[id].id = id
gs[id].result = (id + 1)* 100
}(i)
}
//wg.Wait()
fmt.Printf("%+v\n",gs)
输出为:
程序并发,未等到多个任务结束时就退出进程
var wg sync.WaitGroup
var gs [5]struct { //用于实现类似TLS的功能
id int //编号
result int //返回值
}
for i := 0;i < len(gs) ;i++ {
wg.Add(1)
go func (id int){ //使用参数避免闭包求值延迟
defer wg.Done()
gs[id].id = id
gs[id].result = (id + 1)* 100
}(i)
}
wg.Wait()
fmt.Printf("%+v\n",gs)
}
期望输出:
Goexit
goexit立即终止当前任务;
不会影响其他并发任务,不会引发panic。
在main.main中调用Goexit,他会等待其他任务结束,然后让进程直接崩溃。
(听起来很任性hhh)
通道channel
底层看来,通道相当于一个队列。
同步模式:发送和接收方配对,直接将数据赋值给对方;配对失败时,进入等待队列,知道另一方出现后唤醒。
必须有配对操作的goroutine出现,否则阻塞。
异步模式:抢夺数据缓冲槽,发送方需要写入,接收方需要缓冲数据可读。
异步通道有助于提升性能,减少排队阻塞。
此外,通道还被用作事件通知。
//信号通知
done := make(chan struct{}) //结束事件
//chan struct{}:不能被写入任何数据,不占用任何内存。
//必须通过close进行关闭操作才能输出
c := make(chan string) //数据传输通道
go func(){
s := <-c //接收消息
println(s)
close(done) //关闭消息,作为结束通知
}()
c <- "hello!" //发送消息
println(c) //输出地址?
<-done //阻塞,直到有数据或通道关闭
//异步
c1 := make(chan int,3) //创建带有3个缓冲槽的异步通道
c1 <- 1
c1 <- 2
println(<-c1)
println(<-c1)
//println(<-c1) //会报错:fatal error: all goroutines are asleep - deadlock!
通道变量本身就是指针可以判断是否为同一对象或者nil。
可用cap和len函数判断同步/异步,同步通道两者都返回0.
cap:返回已缓冲数量
len:返回缓冲区大小
println("c:",len(c),cap(c))
println("c1:",len(c1), cap(c1))
输出:
var wg sync.WaitGroup
ready := make(chan struct{})
for i := 0 ; i < 3 ;i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
println(id, ":ready!")
<-ready
println(id, ":running!")
}(i)
}
time.Sleep(time.Second)
println("Ready?Go!")
close(ready) //peng!
wg.Wait()
输出:并发事件不保证输出顺序(?)
已关闭通道:
发送数据->引发panic
接收数据->返回已缓冲数据或零值
nil通道:
收发都会阻塞
单向通道
使用类型转换获取单向通道,并分别赋予操作双方
//单向操作
var wg sync.WaitGroup
wg.Add(2) //收 发,参数为2
c1way := make(chan int)
var send chan<- int = c1way
var recv <-chan int = c1way
go func() {
defer wg.Done()
for x := range recv {
println(x)
}
}()
go func(){
defer wg.Done()
defer close(c1way)
for i := 5; i < 9 ; i++{
send <- i
}
}()
wg.Wait()
//禁止逆向操作
//<- send //invalid operation: <-send (receive from send-only type chan<- int)
//recv <- 1 //invalid operation: recv <- 1 (send to receive-only type <-chan int)
//close(recv) //invalid operation: close(recv) (cannot close receive-only channel)
//单向不可逆
//c2ways := (chan int)(recv) //cannot convert recv (type <-chan int) to type chan int
//c2ways = (chan int)(send) //cannot convert send (type chan<- int) to type chan int
输出结果:
通道还可以实现信号量机制
以及同步。