package main
import (
"fmt"
"time"
)
// go的并发
// 需要通过go关键字来开启goroutine,goroutine属于轻量级线程,goroutine的调度是由Golang运行时进行管理的,这里可以参考我的第一篇关于go的文章
// goroutine语法格式:go 函数名(参数列表)
// go语句开启一个新的运行线程,那么goroutine将以一个不同的新建立的goroutiine来执行一个函数,但是同一个程序的所有goroutine共享同一个地址空间
// channel通道:用于两个goroutine之间通过传递一个指定类型的值来进行同步运行和通讯,操作符<-用于指向通道的方向,处于发送还是接受
// 这里还是引用菜鸟教程里的例子
/*
ch <- v //把v发送到通道ch
v := <-ch //从ch接收数据并将值赋值给v
声明通道:通道名 := make(chan 类型, 缓冲区大小)
声明通道用了chan关键字,记住通道在使用前必须要先创建,在默认情况下通道不带缓冲区。
发送端发了数据在接收端必须要有相应的来接收数据
*/
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(time.Millisecond * 100) //两个goroutine随即执行
fmt.Println(s)
}
}
func sum(s []int, c chan int) {
sum := 0
for _, num := range(s) {
sum = sum + num
}
c <- sum //在这里把sum值发送给到通道c
}
func getCh(n int, cha chan int){
for i := 0; i < n; i++ {
cha <- i
}
close(cha)
}
func main() {
// go并发通过goroutine,使用go关键字建立线程
go say("goroutine 1")
say("goroutine 2")
// 通道部分
var s = []int{2, 3, 4, -1, 9, -4}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
//x := <- c
//y := <- c
x, y := <-c, <-c
fmt.Println(x, y, x+y) //4 9 13
/*
带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。
但是缓冲区的大小是有限的,所以必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。
如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;
如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞
*/
//当定义了带缓冲的通道时,我们就可以同时发送两个数据,而无需立刻同步读取数据
ch1 := make(chan int, 3)
ch1 <- 1
ch1 <- 2
ch1 <- 3
//ch1 <- 4 //当缓存区满了,这个时候再有发送过来的数据就会报错,报严重错误
fmt.Println(<-ch1) //1
fmt.Println(<-ch1) //2
fmt.Println(<-ch1) //3
// go的通道遍历与关闭通道
/*
go可以range来遍历读取通道中的数据,类似数组与切片
num, ok := <- ch
当ok=false时,即为通道接收不到数据了,这时通道可以使用close()函数关闭通道
*/
cha := make(chan int, 10)
go getCh(cap(cha), cha)
//如果不close通道,那么range函数就不会结束,所以在接收完第十个数,准备接受第十一个数时就会阻塞
for i := range cha{
fmt.Println(i)
}
}