使用goroutine和channel实现一个计算int64随机数各位和的程序
- 开启一个goroutine循环生成int64类型的随机数,发送到jobChan
- 开启24个goroutine 从jobChan取出随机数并计算各位各位数的和,将结果发送到resultChan
- 主goroutine从resultChan取出结果并打印到终端输出
代码实现
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
type job struct {
value int64
}
type result struct {
job *job
sum int64
}
var jobChan = make(chan *job, 100)
var resultChan = make(chan *result, 100)
var wg sync.WaitGroup
func producer(pu chan<- *job) {
defer wg.Done()
// 循环生成int64的随机数,发送到jobChan
for {
x := rand.Int63()
newJob := &job{
value: x,
}
pu <- newJob
time.Sleep(time.Second)
}
}
// pu <-chan *job 代表jobChan只读 cm chan<- *result 代表resultChan只写
func consumer(pu <-chan *job, cm chan<- *result) {
defer wg.Done()
// 从jobChan中取出随机数计算各位数的和,将结果发送给resultChan
for {
job := <-pu
sum := int64(0)
n := job.value
for n > 0 {
sum += n % 10
n = n / 10
}
newResult := &result{
job: job,
sum: sum,
}
cm <- newResult
}
}
func main() {
wg.Add(1)
go producer(jobChan)
//开启24个goroutine执行consumer
wg.Add(24)
for i := 0; i < 25; i++ {
go consumer(jobChan, resultChan)
}
// 主goroutine从resultChan中取出结果并打印
for result := range resultChan {
fmt.Printf("value:%d sum:%d\n", result.job.value, result.sum)
}
wg.Wait()
}
涉及知识点:单向channel
默认情况下,通道是双向的,也就是,既可以往里面发送数据也可以同里面接收数据。
但是,我们经常见一个通道作为参数进行传递而值希望对方是单向使用的,要么只让它发送数据,要么只让它接收数据,这时候我们可以指定通道的方向。
单向channel变量的声明非常简单,如下:
var ch1 chan int // ch1是一个正常的channel,不是单向的
var ch2 chan<- float64 // ch2是单向channel,只用于写float64数据
var ch3 <-chan int // ch3是单向channel,只用于读取int数据
- chan<- 表示数据进入管道,要把数据写进管道,对于调用者就是输出。
- <-chan 表示数据从管道出来,对于调用者就是得到管道的数据,当然就是输入。
可以将 channel 隐式转换为单向队列,只收或只发,不能将单向 channel 转换为普通 channel:
示例代码(不需要运行,只需build编译即可检测语法问题):
package main
func main() {
//创建一个channel,双向的
ch := make(chan int)
//双向channel能够隐式转换为单向channel
var writeCh chan<- int = ch //只能写不能读
var readCh <-chan int = ch //只能读不能写
writeCh <- 666 //写
//<-writeCh //err,invalid operation: <-writeCh (receive from send-only type chan<- int)
<-readCh //读
//readCh<-666 //err,invalid operation: readCh <- 666 (send to receive-only type <-chan int)
//注意:单向无法转换为双向
//var ch2 chan int = writeCh //err,cannot use writeCh (type chan<- int) as type chan int in assignment
}
单向channel的应用
package main
import (
"fmt"
)
func producer(out chan<- int) {
for i := 0; i < 10; i++ {
out <- i * i
}
close(out)
}
func consumer(in <-chan int) {
for num := range in {
fmt.Println("num = ", num)
}
}
func main() {
//创建一个双向通道
ch := make(chan int)
//生产者,生产数字,写入channel
//新开一个协程
go producer(ch)
//消费者,从channel中读取内容,进行打印
consumer(ch)
}