sort包
管道,channel
Go推荐使用channel进行通信,原则,不使用共享内存进行通信,而基于通信共享内存
管道本质上是线程安全的队列,管道是引用类型。
通道可用于两个 goroutine 之间通过传递一个指定类型的值
读写
ch := make(chan int, 100) //双向通道
ch := make(<-chan int, 100) //只读通道
ch := make(chan<- int, 100) //只写通道
- 发送方向管道发送一条数据
- 无缓冲区时,发送方阻塞,必须等到接收方接收该数据阻塞结束
- 有缓冲区时
- 缓冲区满,发送方阻塞,必须等到接收方从缓冲区获取一条数据,然后发送方才能将要发送的数据放到缓冲区,随后阻塞结束
- 缓冲区未满,发送方将数据放置缓冲区,不阻塞
- 接收方从管道接收一条数据
- 无缓冲区时,接收方阻塞,必须等到发送方发送一条数据
- 有缓冲区时
- 缓冲区空,接收方阻塞,必须等到发送方发送一条数据,然后接收方才能从缓冲区获取一条数据,随后阻塞结束
- 缓冲区非空,接收方从缓冲区获取一条数据,不阻塞
基于上述特点可以实现:
- 同步通信:无缓冲区的管道
- 异步通信:有缓冲区的管道
package main
import (
"fmt"
)
func main() {
intChannel := make(chan int, 3)
fmt.Printf("%v %v %v\n", intChannel, len(intChannel), cap(intChannel))
intChannel <- 1
intChannel <- 2
intChannel <- 3
//intChannel <- 4
//0xc000078100fatal error: all goroutines are asleep - deadlock!
//放不进去会阻塞,Go检测到无法解除阻塞,所以直接报错
var num int
var ok bool
num, ok = <-intChannel
fmt.Println(num, ok)
num = <-intChannel //可以只取值
<-intChannel //取出但不存储
//num = <-intChannel
//fatal error: all goroutines are asleep - deadlock!
//取不出来会阻塞,Go检测到无法解除阻塞,所以直接报错
close(intChannel)
num, ok = <-intChannel
fmt.Println(num, ok)
}
遍历管道
func close
关闭管道,通道必须可写,应当由发送者执行,在最后的值从已关闭的信道中被接受后,任何对其读操作都会无阻塞成功
x, ok := <-channel
没有数据时,x为对应类型默认值,ok为false
package main
import "fmt"
func main() {
intChannel := make(chan int, 10)
for i := 0; i < 10; i++ {
intChannel <- i
}
close(intChannel)
for i := range intChannel {
fmt.Println(i)
}
fmt.Printf("%v %v %v\n", intChannel, len(intChannel), cap(intChannel))
}
将双向管道赋值给一个单向管道类型变量,达到控制访问目的
只读只写,将一个双向的管道作为只写管道传入函数,防止函数内部修改
package main
func main() {
var intChannelOnlySend chan<- int
intChannelOnlySend = make(chan int, 10)
for i := 0; i < 5; i++ {
intChannelOnlySend <- i
}
//<-intChannel //invalid operation: cannot receive from send-only channel intChannel (variable of type chan<- int)
var intChannelOnlyReceive <-chan int
intChannelOnlyReceive = make(chan int, 10)
<-intChannelOnlyReceive
}
select多路复用
package main
import (
"fmt"
"time"
)
func main() {
// 一个int管道
var intChannel chan int
intChannel = make(chan int, 10)
// 每隔1s向int管道放一个1
go func() {
for {
time.Sleep(time.Second)
intChannel <- 1
}
}()
// 一个string管道
stringChannel := make(chan string, 10)
// 每秒向string管道放一个string
go func() {
for {
time.Sleep(time.Second)
stringChannel <- "string"
}
}()
// 管道select多路复用
for {
time.Sleep(time.Second)
select {
case v := <-intChannel:
fmt.Println(v)
case v := <-stringChannel:
fmt.Println(v)
default:
fmt.Println("nil")
}
}
}
多路复用停止
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
由于Go除内置类型之外没有额外支持数据类型,故需要三方库支持。
Go数据结构与算法库推荐:
https://awesome-go.com/data-structure-and-algorithm-collections/
GoDS: