go(基础02)——信道(channel)

1. 信道的概念

通过使用信道,数据也可以从一端发送,在另一端接收。

2. 信道的定义

所有信道都关联了一个类型。信道只能运输这种类型的数据,而运输其他类型的数据都是非法的。

chan T 表示 T 类型的信道。

信道的零值为 nil。信道的零值没有什么用,应该像对 map 和切片所做的那样,用 make 来定义信道。例如:

a := make(chan int)
package main

import (
	"fmt"
)

func main() {
	var a chan int
	if a == nil {
		fmt.Println("channel a is nil, going to define it")
		a = make(chan int)
		fmt.Printf("Type of a is %T", a)
	}
}

运行结果:

3. 信道的发送和接收

data := <- a   // 读取信道a,并将数据保存至data 
a <- data      // 将data数据写入信道a

注意: 信道的发送和接收是阻塞的。

package main

import (
	"fmt"
)

func hello(done chan bool) {
	fmt.Println("Hello world goroutine")

	done <- true
}

func main() {
	done := make(chan bool)  //创建信道

	go hello(done)
	<-done
	fmt.Println("main function")
}

运行结果:

4. 死锁

产生的原因:

1)一个go协程发送数据,没有其他协程接收数据

2)一个go协程等待接收数据,没有其他协程发送数据

package main

func main() {
	ch := make(chan int)
	ch <- 5
}

执行结果:

5. 单向信道

创建一个只能发送数据的信道:

package main

import "fmt"

func sendData(sendch chan<- int) {
	sendch <- 10
}

func main() {
	sendch := make(chan<- int) //创建一个只发送信道

	go sendData(sendch)
	fmt.Println(<-sendch)      //error:此处无法读取
}

执行结果:

6. 信道关闭

数据发送方可以关闭信道,通知接收方这个信道不再有数据发送过来。

当从信道接收数据时,接收方可以多用一个变量来检查信道是否已经关闭。

v, ok := <- ch   //ok为false,则为读取一个关闭的信道
package main

import (
	"fmt"
)

func producer(chnl chan int) {
	for i := 0; i < 10; i++ {
		chnl <- i
	}
	close(chnl)  //close为关闭信道 
}

func main() {
	ch := make(chan int)
	go producer(ch)
	for {
		v, ok := <-ch
		if ok == false {
			break  //信道关闭 直接跳出循环
		}
		fmt.Println("Received ", v, ok)
	}
}

执行结果:

注意:for range 循环用于在一个信道关闭之前,从信道接收数据。

package main

import (
	"fmt"
)

func producer(chnl chan int) {
	for i := 0; i < 10; i++ {
		chnl <- i
	}
	close(chnl)
}

func main() {
	ch := make(chan int)
	go producer(ch)
	for v := range ch {
		fmt.Println("Received ", v)
	}
}

执行结果:

7. 练习

计算一个数中每一位的平方和和立方和,然后将平方和和立方和相加并打印。

package main

import (
	"fmt"
)

func digits(number int, dchnl chan int) {
	for number != 0 {
		digit := number % 10
		dchnl <- digit
		number /= 10
	}
	close(dchnl)
}
func calcSquares(number int, squareop chan int) {
	sum := 0
	dch := make(chan int)
	go digits(number, dch)
	for digit := range dch {
		sum += digit * digit
	}
	squareop <- sum
}

func calcCubes(number int, cubeop chan int) {
	sum := 0
	dch := make(chan int)
	go digits(number, dch)
	for digit := range dch {
		sum += digit * digit * digit
	}
	cubeop <- sum
}

func main() {
	number := 589
	sqrch := make(chan int)
	cubech := make(chan int)
	go calcSquares(number, sqrch)
	go calcCubes(number, cubech)
	squares, cubes := <-sqrch, <-cubech
	fmt.Println("Final output", squares+cubes)
}

执行结果:

猜你喜欢

转载自blog.csdn.net/www_dong/article/details/114242426