Channel小結
一:channel的一些特性
1.盡量避免使用鎖來解決臨界資源安全問題
2.通道的角色必須在兩個及以上
3.chan,必須要作用在兩個以上的goroutine
二:通道的聲明
點擊查看代碼
func main() {
//聲明+賦值
var c chan int
c = make(chan int, 10)
/*//存,取
//存
c <- 1
//取
data := <-c
fmt.Println(data)*/
go func() {
time.Sleep(5*time.Second)
c <- 2
}()
// 另一個goroutine可以從通道中取數據
//阻塞等待c通道寫入數據。如果沒人寫只有讀,就會一直阻塞
data := <- c
fmt.Println("ch data;", data)
}
三:死鎖產生的情況
1.單線程無法消費channel,寫入一個數據至channel,卻沒人來消費這個數據,會導致阻塞
2.兩個channel互相需要對方的數據,但是由于判斷(select監聽),拿不到對方的數據
3.sync鎖產生的死鎖
4.接收端等待,沒有寫入端
四:通道關閉
我們需要將通道手動關閉的目的,是為了告訴讀取端,寫入端的所有數據已寫入完畢
我們通常也會將for range和close進行搭配使用,for range在close關閉后且已經讀取完通道內的數據后,就會自動退出for循環
點擊查看代碼
import "fmt"
func main() {
chan1 := make(chan int) //通道可以當做參數傳遞
go test1(chan1)
//讀取chan中的數據
/*for {
time.Sleep(1 * time.Second)
//判斷chan狀態是否關閉,如果關閉,就不會取值了
data1, ok := <-chan1
if !ok {
fmt.Println("讀取完畢")
break
}
fmt.Println("ch data1", data1) //這種是原始寫法
}*/
//讀取chan中的數據,for 一個個取,并且會自動判斷通道是否關閉
for v := range chan1{
time.Sleep(1*time.Second)
fmt.Println(v)
}
fmt.Println("end")
}
func test1(ch chan int) {
for i := 0; i < 10; i++ {
ch <- i
}
//關閉通道,告訴接收方,我不會再有其他數據發送到chan中了
close(ch)
}
五:緩沖通道
帶了一個緩沖區的通道,只有當通道全部被寫滿后才會被阻塞
點擊查看代碼
package main
import (
"fmt"
"time"
)
func main() {
//緩沖通道
//緩沖區通道,放入數據,不會產生死鎖,它不需要等待其他線程來拿,它可以放多個數據
//如果緩沖區滿了,還沒有人取,還會產生死鎖
ch := make(chan int, 4)
fmt.Println(cap(ch), len(ch))
go test1(ch)
for v := range ch {
time.Sleep(1 * time.Second)
fmt.Println("main讀取數據", v)
}
fmt.Println("main-end")
}
func test1(ch chan int) {
for i := 0; i < 10; i++ {
ch <- i
fmt.Println("放入數據:", i)
}
close(ch)
}
六:單向通道
在函數中,我們通常會要求這個通道只用于讀數據,當我們操作失誤,這里出現了寫入,這就會造成混亂
我們通常將單向通道作為函數的形參傳遞,只能讀或者只能寫
點擊查看代碼
package main
import (
"fmt"
"time"
)
func main() {
ch1:=make(chan int,10)
ch1<-100
data:=<-ch1
fmt.Println(data)
//單向通道
ch2:=make(chan<-int,1) //只能寫數據,不能讀
ch2<-100
//data:=<-ch2 會報錯
//ch3:=make(<-chan int,1) //只能讀數據,不能寫
//ch3<-100 會報錯
//使用場景
ch4:=make(chan int) //可讀可寫
go writeOnly(ch4)
go readOnly(ch4)
time.Sleep(5*time.Second)
}
//指定函數去寫,不讓他讀取,防止通道濫用
func writeOnly(ch chan <-int) {
//函數內部處理寫數據的操作
ch <- 100
//嘗試讀操作
}
//指定函數去讀,不讓他寫入,防止通道濫用
func readOnly(ch<-chan int) {
data:=<-ch
fmt.Println(data)
}
七:timer定時器
可以控制程序在某個時間點做某個事情
點擊查看代碼
package main
import (
"fmt"
"time"
)
func main() {
timer := time.NewTimer(3 * time.Second)
//創建了一個timer對象
//C <-chan Time
//timer對象中的字段是一個channel,而且是一個讀取的單向通道,我們將其賦值出來
//timeChan:=timer.C //這就是一個單向通道
fmt.Println(<-timer.C) //打印了定時器通道中存儲的時間
//上面我們將里面的時間寫入了通道,然后我們再通過讀單向通道將其讀取出來
}
//定時器(提前關閉)
//當我們創建一個定時器,會向Timer.C的通道中放入一個時間
//當我們在下面消費這個通道的時間后,這個就不會阻塞了,直接就結束了
timer2 := time.NewTimer(time.Second * 5)
go func() {
<-timer2.C //消費
fmt.Println("end")
}()
timer2.Stop() //手動停止定時器

浙公網安備 33010602011771號