goroutine计算自然数的和——拆分task、channel、WaitGroup、线程池、done

功能

计算100个自然数的和。

1 退出通知机制实现

1.1 程序逻辑

  1. InitTask函数构建task并发送到task通道。
  2. 分发任务函数DistributeTask为每个task启动goroutine处理任务,并等待其处理完成,然后关闭通道。
  3. ProcessResult函数读取并统计所有的值。
  4. 这几个函数在不同的goroutine中运行,它们通过通道和sync.WaitGroup进行通信与同步。

1.2 代码

package main

import (
	"fmt"
	"sync"
)

//工作任务
type task struct {
	begin  int
	end    int
	result chan<- int //发送
}

//任务执行,计算begin到end的和,并将结果写入chan result
func (t *task) do() {
	sum := 0
	for i := t.begin; i <= t.end; i++ {
		sum += i
	}
	t.result <- sum
}

//构建任务并写入task通道
func InitTask(taskchan chan<- task, r chan int, p int) {
	qu := p / 10
	mod := p % 10
	high := qu * 10
	for j := 0; j < qu; j++ {
		b := 10*j + 1
		e := 10 * (j + 1)
		tsk := task{
			begin:  b,
			end:    e,
			result: r,
		}
		taskchan <- tsk
	}
	if mod != 0 {
		tsk := task{
			begin:  high + 1,
			end:    p,
			result: r,
		}
		taskchan <- tsk
	}
	close(taskchan)
}

//读取task chan,每个task启动一个worker goroutine进行处理,并等待task运行完,关闭通道
func DistributeTask(taskchan <-chan task, wait *sync.WaitGroup, result chan int) {
	for v := range taskchan {
		wait.Add(1)
		go ProcessTask(v, wait)
	}
	wait.Wait()
	close(result)
}

//处理的具体工作
func ProcessTask(t task, wait *sync.WaitGroup) {
	t.do()
	wait.Done()
}

//读取结果通道,汇总结果
func ProcessResult(resultchan chan int) int {
	sum := 0
	for r := range resultchan {
		sum += r
	}
	return sum
}

func main() {
	//创建任务通道
	taskchan := make(chan task, 10)

	//创建结果通道
	resultchan := make(chan int, 10)

	//用于同步等待任务执行
	wait := &sync.WaitGroup{}

	//初始化task的goroutine 计算100的和
	go InitTask(taskchan, resultchan, 100)

	//每个task启动一个worker goroutine进行处理
	go DistributeTask(taskchan, wait, resultchan)

	//获取结果并统计
	sum := ProcessResult(resultchan)

	fmt.Println(sum)

}

在这里插入图片描述

2 线程池和done信号机制

2.1 程序逻辑

  1. 构建task并发送到task通道中
  2. 分别启动多个工作线程,不停滴从task中获取任务,将结果写入结果通道,如果任务通道被关闭,则负责向收敛结果的goroutine发送通知,告诉他workers已完成工作
  3. goroutine接收到task已完成的信号时,主动关闭结果通道
  4. main中函数进行读取并统计所有的结果

2.2 代码

package main

import (
	"fmt"
)

//线程池
const (
	NUMBER = 10
)

//工作任务
type task struct {
	begin  int
	end    int
	result chan<- int //发送
}

//任务执行,计算begin到end的和,并将结果写入chan result
func (t *task) do() {
	sum := 0
	for i := t.begin; i <= t.end; i++ {
		sum += i
	}
	t.result <- sum
}

//构建任务并写入task通道,结果写入r通道
func InitTaskforPool(taskchan chan<- task, r chan int, p int) {
	qu := p / 10
	mod := p % 10
	high := qu * 10
	for j := 0; j < qu; j++ {
		b := 10*j + 1
		e := 10 * (j + 1)
		tsk := task{
			begin:  b,
			end:    e,
			result: r,
		}
		taskchan <- tsk
	}
	if mod != 0 {
		tsk := task{
			begin:  high + 1,
			end:    p,
			result: r,
		}
		taskchan <- tsk
	}
	close(taskchan)
}

//读取task chan,每个task启动一个worker goroutine进行处理
func DistributeTaskforPool(taskchan <-chan task, workers int, done chan struct{}) {
	for i := 0; i < workers; i++ {
		go ProcessTaskforPool(taskchan, done)
	}
}

//处理的具体工作,结果写入result通道
func ProcessTaskforPool(taskchan <-chan task, done chan struct{}) {
	for t := range taskchan {
		t.do()
	}
	done <- struct{}{}
}

//通过done同步等待所有工作的goroutine结束,关闭结果chan
func CloneResult(done chan struct{}, resultchan chan int, workers int) {
	for i := 0; i < workers; i++ {
		<-done
	}
	close(done)
	close(resultchan)
}

//读取结果通道,汇总结果
func ProcessResult(resultchan chan int) int {
	sum := 0
	for r := range resultchan {
		sum += r
	}
	return sum
}

func main() {

	//线程池大小
	workers := NUMBER

	//创建任务通道
	taskchan := make(chan task, 10)

	//创建结果通道
	resultchan := make(chan int, 10)

	//信号通道
	done := make(chan struct{}, 10)

	//初始化任务,taskchan通道写入多个小task,result写入多个小result
	go InitTaskforPool(taskchan, resultchan, 100)

	//分发任务给多个workers
	DistributeTaskforPool(taskchan, workers, done)

	//获取停止信号后,关闭结果通道
	go CloneResult(done, resultchan, workers)

	sum := ProcessResult(resultchan)

	fmt.Println(sum)

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值