golang 使用chan+goroutine 实现workpool线程池

使用goroutine和channel实现一个计算int64随机数各位和的程序

  1. 开启一个goroutine循环生成int64类型的随机数,发送到jobChan
  2. 开启24个goroutine 从jobChan取出随机数并计算各位各位数的和,将结果发送到resultChan
  3. 主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数据
  1. chan<- 表示数据进入管道,要把数据写进管道,对于调用者就是输出。
  2. <-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)

}
  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值