工作池WorkPool

工作池

一般而言,工作池就是一组等待任务分配的协程。一旦完成了所分配的任务,这些线程可继续等待任务的分配。

我们会使用缓冲信道来实现工作池。我们工作池的任务是计算所输入数字的每一位的和。例如,如果输入 234,结果会是 9(即 2 + 3 + 4)。向工作池输入的是一列伪随机数。

我们工作池的核心功能如下:

  • 创建一个 Go 协程池,监听一个等待作业分配的输入型缓冲信道。
  • 将作业添加到该输入型缓冲信道中。
  • 作业完成后,再将结果写入一个输出型缓冲信道。
  • 从输出型缓冲信道读取并打印结果。
import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

// 创建结构体,用来表示作业和结果
type Job struct {
    id int
    randomno int
}

type Result struct{
    job Job
    randomno int
}

// 创建用于读取作业和写入结果的缓冲信道
var jobs = make(chan Job, 10)
var results = make(chan Result, 10)

// 创建用于完成作业的协程
func digits(numbers int) int {
    sum := 0
    no := numbers
    for no != 0 {
        sum += no % 10
        no /= 10
    }
    return sum
}

// 创建worker协程监听jobs中的作业,一旦工作协程完成了当前作业,就将其结果写入results
func worker(wg *sync.WaitGroup) {
    for job := range jobs {
        output := Result{job, digits(job.randomno)} // 创建结构体用于存放job的结果
        results <- output
    }
    wg.Done()
}

// 创建worker协程的工作池以达到并发地完成jobs中作业的效果
func creatWorkerPool(noOfWorkers int) {
    var wg sync.WaitGroup
    for i := 0; i < noOfWorkers; i++ {
        wg.Add(1)
        go worker(&wg) 
    }
    wg.Wait()
    close(results)
}

// 创建allocate协程向jobs写入作业
func allocate(noOfJobs int) {
    for i := 0; i < noOfJobs; i++ {
        randomno := rand.Intn(999)
        job := Job{i, randomno}
        jobs <- job
    }
    close(jobs)
}

// 创建result协程监听并打印results中的结果
func result(done chan bool){
    for result := range results {
        //time.Sleep(1 * time.Second)// 模拟耗时场景
        fmt.Printf("Job id %d, input random no %d, sum of digits %d\n", result.job.id, result.job.randomno, result.randomno)
    }
    done <- true
}

//文中的第67、80行注释是为了测试go result(done)中的done是否可以去掉,
//测试结果:不可以去掉,当给result()中设置模拟耗时场景时可从输出结果看出并未输出或未
//输出完整的results,因为result()并发执行时没有done信道阻塞主协程main(),所以当main()//正常执行完毕退出时result()仍为完全打印出所有results
//在加入done后即使模拟result()耗时场景也会因为done阻塞主协程而强制等待result()完全输出

func main(){
    startTime := time.Now()
    jobs := 100 //修改100为10减少不必要耗时
    go allocate(jobs)
    done := make(chan bool)
    go result(done)
    workers := 10
    creatWorkerPool(workers) //可以不go此函数,即使go了,下一行代码还是处于阻塞main协程的状态
    <- done
    endTime := time.Now()
    diff := endTime.Sub(startTime)
    fmt.Println("total time taken ",diff.Seconds(), "seconds") //打印总耗时
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值