channel通道
package main
import "fmt"
//15
func main() {
/*
channel
*/
var a chan int
fmt.Printf("%T,%v\n",a,a) //chan int,<nil>
if a == nil {
fmt.Println("channel是nil的,不能使用,需要先創(chuàng)建通道")
a = make(chan int)
fmt.Println(a) //0xc00008c060
}
test1(a)
var ch1 chan bool
ch1 = make(chan bool)
go func() {
for i := 0; i < 10; i++ {
fmt.Println("子goroutine:",i)
}
//循環(huán)結(jié)束,向通道中寫數(shù)據(jù)
ch1 <- true
fmt.Println("結(jié)束。。。") //結(jié)束。。。
}()
//寫之前讀阻塞,讀之前寫阻塞
data := <- ch1
fmt.Println("main data --->",data) //main data ---> true
fmt.Println("main over") //main over
}
func test1(ch chan int){
fmt.Printf("%T,%v\n",ch,ch) //chan int,0xc000100060
}
關(guān)閉通道和通道上范圍循環(huán)
package main
import (
"fmt"
"time"
)
//16
func main() {
/*
關(guān)閉通道:close(ch)
子groutine,寫出10個(gè)數(shù)據(jù)
每寫一個(gè),阻塞一次,主goroutine讀取一次,解除阻塞
主goroutine,讀取數(shù)據(jù)
每次讀取數(shù)據(jù),阻塞一次,子goroutine,寫出一個(gè),解除阻塞
*/
ch1 := make(chan int)
go sendData(ch1)
//讀取通道的數(shù)據(jù)
for{
time.Sleep(1 * time.Second)
v,ok := <- ch1
if !ok {
fmt.Println("已經(jīng)讀取了所有數(shù)據(jù)",v,ok)
break
}
fmt.Println("讀取的數(shù)據(jù):",v,ok)
}
fmt.Println("main over")
}
func sendData(ch1 chan int) {
//發(fā)送方
for i := 0; i < 10; i++ {
ch1 <- i
}
close(ch1)
}
package main
import (
"fmt"
)
//17
func main() {
/*
通過(guò)range訪問(wèn)通道
*/
ch1 := make(chan int)
go sendData2(ch1)
//range來(lái)訪問(wèn)通道
for v := range ch1 {
fmt.Println("讀取數(shù)據(jù):",v)
}
fmt.Println("main over")
}
func sendData2(ch1 chan int) {
//發(fā)送方
for i := 0; i < 10; i++ {
ch1 <- i
}
close(ch1) //通知對(duì)方通道關(guān)閉
}
緩沖通道
package main
import (
"fmt"
"strconv"
)
//18
func main() {
/*
非緩沖通道:make(chan T)
一次發(fā)送,一次接受,都是阻塞的
緩沖通道:make(chan T,capacity)
發(fā)送:緩沖區(qū)的數(shù)據(jù)滿了,才會(huì)阻塞
接收:緩沖區(qū)的數(shù)據(jù)空了,才會(huì)阻塞
*/
ch1 := make(chan int)
fmt.Println(len(ch1), cap(ch1)) //0 0
ch2 := make(chan int, 5)
fmt.Println(len(ch2), cap(ch2)) //0 5
ch2 <- 100
fmt.Println(len(ch2), cap(ch2)) //1 5
ch2 <- 100
ch2 <- 200
ch2 <- 300
ch2 <- 400
fmt.Println(len(ch2), cap(ch2)) //5 5
// ch2 <- 600 //fatal error: all goroutines are asleep - deadlock!
fmt.Println("-------------")
ch3 := make(chan string, 4)
go sendData3(ch3)
for{
v,ok := <-ch3
if !ok {
fmt.Println("讀完了..",ok)
break
}
fmt.Println("\t讀取的數(shù)據(jù)是:",v)
}
fmt.Println("main over...")
}
func sendData3(ch chan string){
for i := 0; i < 10; i++ {
ch <- "數(shù)據(jù)" + strconv.Itoa(i)
fmt.Println("子goroutine中寫出第 %d 個(gè)數(shù)據(jù)\n",i)
}
close(ch)
}
定向通道
package main
import "fmt"
//19
func main() {
/*
雙向通道
chan T
chan <- data,發(fā)送數(shù)據(jù),寫出
data <- chan,獲取數(shù)據(jù),讀取
單向:定向
chan <- T,只支持寫操作
<- chan T,只讀
*/
ch1 := make(chan string)
done := make(chan bool)
go sendData4(ch1, done)
data := <- ch1
fmt.Println("子goroutine傳來(lái):",data) //子goroutine傳來(lái): isuntong
ch1 <- "isuntong2"
<- done //不通知不要結(jié)束
fmt.Println("main over...")
}
func sendData4(ch1 chan string, done chan bool) {
ch1 <- "isuntong"
data := <- ch1
fmt.Println("main goroutine傳來(lái):",data)
done <- true
}
package main
import "fmt"
//20
func main() {
/*
單向:定向
chan <- T,只支持寫操作
<- chan T,只讀
用作默寫函數(shù)保護(hù)
函數(shù)內(nèi)部對(duì)于ch1只能讀,不能寫,所以可以保護(hù)安全
創(chuàng)建雙向channel,在某些函數(shù)中限定只讀只寫,作為保護(hù)。
*/
ch1 := make(chan int) //雙向,讀寫
//ch2 := make(chan <- int) //單向,只能寫
//ch3 := make(<- chan int) //單向,只能讀
// ch2 <- 1000
// data := <-ch2 //invalid operation: <-ch2 (receive from send-only type chan<- int)
// data := <- ch3
// ch3 <- 2000 //invalid operation: ch3 <- 2000 (send to receive-only type <-chan int)
// fmt.Println(data)
go fun3(ch1) //可讀可寫
// fun3(ch2)
data2 := <- ch1
fmt.Println("fun3函數(shù)寫出的數(shù)據(jù)是:",data2) //fun3函數(shù)寫出的數(shù)據(jù)是: 100
}
//該函數(shù),只能操作只寫的通道
func fun3(ch chan <- int) {
ch <- 100
fmt.Println("fun3函數(shù)結(jié)束") //fun3函數(shù)結(jié)束
}
func fun4(ch <- chan int) {
fmt.Println("fun3函數(shù)結(jié)束") //fun3函數(shù)結(jié)束
}
time包中的通道相關(guān)函數(shù)
package main
import (
"fmt"
"time"
)
//21
func main() {
/*
1. func NewTimer(d Duration) *Timer
創(chuàng)建一個(gè)計(jì)數(shù)器,d時(shí)間以后觸發(fā)
2. func After(d Duration) <- chan Time
返回一個(gè)通道,存儲(chǔ)的是d時(shí)間間隔之后的當(dāng)前時(shí)間
*/
timer := time.NewTimer(3 * time.Second)
fmt.Printf("%T\n",timer) //*time.Timer
fmt.Println(time.Now()) //2020-03-26 19:29:30.612334 +0800 CST m=+0.000112607
//此處等待channel中的數(shù)據(jù),會(huì)阻塞3秒
ch2 := timer.C
fmt.Println(<-ch2) //2020-03-26 19:29:33.614302 +0800 CST m=+3.002032115
//新建一個(gè)計(jì)數(shù)器
timer2 := time.NewTimer(5 * time.Second)
//開(kāi)始goroutine,來(lái)處理觸發(fā)后的事件
go func() {
<- timer2.C
fmt.Println("Timer2結(jié)束")
}()
time.Sleep(3 * time.Second)
flag := timer2.Stop() //停止定時(shí)
if flag {
fmt.Println("Timer2停止了")
}
//After(d Duration)
ch := time.After(3 * time.Second)
fmt.Printf("%T\n",ch) //<-chan time.Time
fmt.Println(time.Now()) //2020-03-26 19:40:21.089133 +0800 CST m=+6.004003279
timer3 := <-ch
fmt.Println(timer3) //2020-03-26 19:40:24.091121 +0800 CST m=+9.005942476
}
select語(yǔ)句
package main
import (
"fmt"
"time"
)
//22
func main() {
/*
分支語(yǔ)句:if、switch、select
select類似于switch語(yǔ)句
但是select語(yǔ)句會(huì)隨機(jī)執(zhí)行一個(gè)可運(yùn)行的case
如果沒(méi)有case可以執(zhí)行,要看是否有default,如果有就執(zhí)行default,否則就進(jìn)入阻塞,直到有case可以運(yùn)行
*/
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(3 * time.Second)
ch1 <- 100
}()
go func() {
time.Sleep(3 * time.Second)
ch2 <- 200
}()
select {
case num1 := <- ch1:
fmt.Println("ch1中獲得數(shù)據(jù)是:", num1)
case num2,ok := <-ch2:
if ok{
fmt.Println("ch2中獲得的數(shù)據(jù)是:",num2)
}else {
fmt.Println("ch2通道已關(guān)閉")
}
default:
fmt.Println("default語(yǔ)句。。。")
}
fmt.Println("main over...")
}
CSP并發(fā)模型