channel(一)
channel用于goroutines之间的通信,让它们之间可以进行数据交换。像管道一样,一个goroutine_A向channel_A中放数据,另一个goroutine_B从channel_A取数据
channel 基本语法
// 因为channel是指针类型的数据类型,所以通过make来分配内存
// 使用make声明一个channel,里面可以存放string类型的数据
channel := make(chan string)
// 将tmp送到channel中
channel <- tmp
// 从channel中接受数据给tmp
tmp := <- channel
// 从channel中接受数据给tmp,如果没有接受到则ok值为false
tmp,ok := <- channel
// 关闭通道channel
close(channel)
无缓冲的通道
没有缓冲的通道,如果routine A向通道中发送了一个数据,那么必须等到这个数据被其他routine 取出之后,才能继续往通道里发送,严格遵循”一进一出“原则,这也就要求两个routine 在同时对同一个通道进行写操作和取操作
- sender端向channel中send一个数据,然后阻塞,直到receiver端将此数据receive
- receiver端一直阻塞,直到sender端向channel发送了一个数据
// 两个routine分别对一个通道进行取放操作,并且对里面的数据+1,到2000截至
// 严格遵循“一进一出”
func Routine01(wg *sync.WaitGroup, count chan int) {
defer wg.Done()
for {
// 从通道中拿取数据
res, ok := <-count
if !ok {
// 说明通道中已经没有数据,或者已被关闭
fmt.Println("finish!")
break
}
fmt.Println(res)
if res == 2000 {
close(count)
break
}
count <- res + 1
}
}
func main() {
var wg sync.WaitGroup
// 新建一个无缓冲的通道count
count := make(chan int)
wg.Add(2)
// 创建两个协程
for i := 0; i < 2; i++ {
go Routine01(&wg, count)
}
// 给管道里送一个数据,来开始操作
count <- 1
wg.Wait()
}
有缓冲的通道
有缓冲的通道,可以控制里面的缓冲区大小,可以借助通道实现异步的取放操作
- 容量:表示buffered channel最多可以缓冲多少个数据
- 长度:表示buffered channel当前已缓冲多少个数据
- 创建buffered channel的方式为
make(chan TYPE,CAP)
// 新建Routine来模拟机器人工作
func Routine02(wg *sync.WaitGroup, count chan string) {
defer wg.Done()
for {
// 从通道中分配工作
tmp, ok := <-count
if !ok {
// 代表通道已经空了,或者已被关闭
fmt.Println("No task else!")
break
}
fmt.Println(tmp + " start!")
time.Sleep(200 * time.Millisecond)
fmt.Println(tmp + " done!")
}
}
func main() {
var wg sync.WaitGroup
// 新建一个缓冲区大小为5的通道,来管理工作
count := make(chan string, 5)
wg.Add(2)
fmt.Println("Work start!")
// 往缓冲区中放一系列待完成的工作
for i := 0; i < 5; i++ {
tmp := fmt.Sprintf("Task %d", i)
count <- tmp
fmt.Println(tmp + " in!")
}
for i := 0; i < 2; i++ {
go functions.Routine(&wg, count)
}
// 关闭通道
close(count)
wg.Wait()
}
文章评论