一、Goroutine协程:协程就是go提供的轻量级的独立运算过程,比线程还轻;建立一个协程,就是使用go关键字,后面跟上要运行的函数异步
案例要求:1)、先计算1000如下全部可以被3整除的整数的和Aide
2)、而后计算1000如下全部可以被5整除的整数和B函数
3)、而后再计算1000如下全部可以被3和5整除的整数和Cspa
4)、使用A+B-C获得最后结果线程
案例中,使用go关键字建立一个协程,协程函数内使用channel(chan数据,相似队列,在取chan中数据时,若是为空,会阻塞,直到chan中有数据)存储数据code
package main import ( "fmt" "runtime" "time" ) func get_sum_of_divisible(num int, divider int, resultChan chan int) { sum := 0 for value := 0; value < num; value++ { if value%divider == 0 { sum += value } } resultChan <- sum } func main() { runtime.GOMAXPROCS(runtime.NumCPU()) LIMIT := 1000 //用于被15除结果 job1 := make(chan int, 1) //用于被3,5除结果 job2 := make(chan int, 2) t_start := time.Now() go get_sum_of_divisible(LIMIT, 15, job1) go get_sum_of_divisible(LIMIT, 3, job2) go get_sum_of_divisible(LIMIT, 5, job2) sum15 := <-job1 sum3, sum5 := <-job2, <-job2 sum := sum3 + sum5 - sum15 t_end := time.Now() fmt.Println(sum) fmt.Println(t_end.Sub(t_start)) }
二、Channel通道:提供了协程之间的通讯方式以及运行同步机制协程
案例:假设训练定点投篮和三分投篮,教练在计数blog
若是向channel里面写信息,必须有配对的取信息的一端;假如把下面的go count(c)注释掉,则不会有打印数据three
package main import ( "fmt" "strconv" "time" ) func fixed_shooting(msg_chan chan string) { i := 1 for { msg_chan <- "fixed shooting" var str string = strconv.Itoa(i) fmt.Println("continue fixed shooting..." + str) i++ } } func count(msg_chan chan string) { for { msg := <-msg_chan fmt.Println(msg) time.Sleep(time.Second * 1) } } func main() { var c chan string c = make(chan string) go fixed_shooting(c) go count(c) var input string fmt.Scanln(&input) }
加一个三分投篮方法,能够看出,写入channel中的数据,必须读取出来才能再次写入,若是没有读取出来,再次写入会失败队列
package main import ( "fmt" "strconv" "time" ) func three_point_shooting(msg_chan chan string) { i := 1 for { var str string = strconv.Itoa(i) msg_chan <- "three point shooting--" + str i++ } } func fixed_shooting(msg_chan chan string) { i := 1 for { var str string = strconv.Itoa(i) msg_chan <- "fixed shooting--" + str i++ } } func count(msg_chan chan string) { for { msg := <-msg_chan fmt.Println(msg) time.Sleep(time.Second * 1) } } func main() { var c chan string c = make(chan string) go fixed_shooting(c) go three_point_shooting(c) go count(c) var input string fmt.Scanln(&input) }
结果图以下,结果是交替输出的,也就是channel中输入的必须输出后才能再次输入
三、Channel通道方向
var c chan string 可读写channel,可写入也可读取
var c chan<- string 只写channel,只能写入
var c <-chan string 只读channel,只能读取
四、多通道(Select)
案例中,select依次检查每一个channel是否有消息传递过来,若是有就输出;若是同时有多个消息到达,select随机选择一个channel来从中读取消息;若是没有一个channel有消息到达,那么select语句就阻塞在这里一直等待。select 语句也能够有default片断,case不符合时会执行default语句片断。select中case、default相似switch中case、default
下面case中使用了time.After,能够这样理解,main函数也是一个channel,time.After让main阻塞指定时间后,读出时间消息(案例中没有用变量存储返回的时间)
package main import ( "fmt" "time" ) func fixed_shooting(msg_chan chan string) { var times = 3 var t = 1 for { if t <= times { msg_chan <- "fixed shooting" } t++ time.Sleep(time.Second * 1) } } func three_point_shooting(msg_chan chan string) { var times = 3 var t = 1 for { if t <= times { msg_chan <- "three point shooting" } t++ time.Sleep(time.Second * 1) } } func main() { c_fixed := make(chan string) c_3_point := make(chan string) go fixed_shooting(c_fixed) go three_point_shooting(c_3_point) go func() { for { select { case msg1 := <-c_fixed: fmt.Println(msg1) case msg2 := <-c_3_point: fmt.Println(msg2) case <-time.After(time.Second * 5): fmt.Println("timeout check again...") } } }() var input string fmt.Scanln(&input) }
结果图
五、Channel Buffer通道缓冲区:通常咱们定义的channel都是同步的,也就是说接受端和发送端彼此等待对方OK才开始。可是若是执行了channel缓冲区大小,那么消息的发送和接收是异步的,除非channel缓冲区已经满了
package main import ( "fmt" "strconv" "time" ) func shooting(msg_chan chan string) { var group = 1 for { for i := 1; i <= 10; i++ { msg_chan <- strconv.Itoa(group) + ":" + strconv.Itoa(i) } group++ time.Sleep(time.Second * 5) } } func count(msg_chan chan string) { for { fmt.Println(<-msg_chan) } } func main() { var c = make(chan string, 20) go shooting(c) go count(c) var input string fmt.Scanln(&input) }