chan - skynocover/Wiki-for-GoLang GitHub Wiki

宣告

chan T //可以用來發送與接收的通道

chan<-T //只能用來發送

<-chan T // 只能用來接收


初始化

ci := make(chan int)     //整数無緩衝

cj := make(chan int, 0)  //整数無緩衝

cp := make(chan *os.File, 100) //指向文件指標有緩衝

緩衝表channel可以容納元素的大小


數據發送

c := make(chan int) //建立通道
defer close(c)
go func() { c <- 3 + 4 }() //計算3+4
i := <-c //等到接收到7之後才動作
fmt.Println(i)

可以用ok確認是否有收到

x, ok := <-ch
x, ok = <-ch
var x, ok = <-ch

close

若channel被關閉還繼續發送會出現panic

func main() {
	go func() {
		time.Sleep(time.Hour)
	}()
	c := make(chan int, 10)
	c <- 1
	c <- 2
	close(c)
	c <- 3
}

但是可以繼續讀取

c := make(chan int, 10)
c <- 1
c <- 2
close(c)
fmt.Println(<-c) //1
fmt.Println(<-c) //2
fmt.Println(<-c) //0
fmt.Println(<-c) //0

使用range則會在關閉後跳出

c := make(chan int, 10)
c <- 1
c <- 2
close(c)
for i := range c {
	fmt.Println(i)
}

range處理

for range

func main() {
	go func() {
		time.Sleep(1 * time.Hour)
	}()
	c := make(chan int)
	go func() {
		for i := 0; i < 10; i = i + 1 {
			c <- i
		}
		close(c)
	}()
	for i := range c {
		fmt.Println(i)
	}
	fmt.Println("Finished")
}

若沒有將c關掉則會一直卡在 for range那一行


使用select

select類似switch 但是只用在chan
參照條目select


使用timer和ticker兩個channel

timer表定時器
下面那個會等待兩秒後才執行

timer1 := time.NewTimer(time.Second * 2)
<-timer1.C
fmt.Println("Timer 1 expired")

也可以用timestop來停止計時

timer2 := time.NewTimer(time.Second)
go func() {
	<-timer2.C
	fmt.Println("Timer 2 expired")
}()
stop2 := timer2.Stop()
if stop2 {
	fmt.Println("Timer 2 stopped")
}

ticker表定時觸發的計時器

下面例子表每500號秒觸發一次

ticker := time.NewTicker(time.Millisecond * 500)
go func() {
	for t := range ticker.C {
		fmt.Println("Tick at", t)
	}
}()

通知任務完成

func worker(done chan bool) {
	time.Sleep(time.Second)
	// 通知任务已完成
	done <- true
}
func main() {
	done := make(chan bool, 1)
	go worker(done)
	// 等待任务完成
	<-done
}