003_对go语言中的工作池代码练习的一些思考和改进

在进行工作池的代码练习时候,我发现了一个有趣的事情,首先看下面一段代码:

package main

import "fmt"
import "time"

func worker(id int, jobs <-chan int, results chan<- int) {
	for j := range jobs {
		fmt.Println("worker", id, "processing job", j)
		time.Sleep(time.Second)
		results <- j * 2
	}
}
func main() {
	jobs := make(chan int, 100)
	results := make(chan int, 100)
	for w := 1; w <= 3; w++ {
		go worker(w, jobs, results)
	}
	for j := 1; j <= 9; j++ {
		jobs <- j
	}
	close(jobs)
	for a := 1; a <= 9; a++ {
		<-results
	}
}

  

上面代码运行结果是下面这样的,会发现3个工人,平均分配了9个工作,每人有3个

 

worker 3 processing job 1
worker 2 processing job 3
worker 1 processing job 2
worker 3 processing job 4
worker 1 processing job 5
worker 2 processing job 6
worker 1 processing job 8
worker 2 processing job 7
worker 3 processing job 9

  

但是,如果将代码改造成下面这样,去掉了工作的时间等待:

 

package main

import "fmt"

func worker(id int, jobs <-chan int, results chan<- int) {
	for j := range jobs {
		fmt.Printf("I am %d working at jobs %d\n", id, j)
		results <- j * 2
	}
}

func main() {
	jobs := make(chan int, 10)
	results := make(chan int, 10)
	for i := 1; i < 4; i++ {
		go worker(i, jobs, results)
	}
	for k := 1; k < 10; k++ {
		jobs <- k
	}
	for v := 1; v < 10; v++ {
		<-results
	}
}

  

那么运行结果变成了下面这样:

I am 3 working at jobs 1
I am 3 working at jobs 4
I am 3 working at jobs 5
I am 3 working at jobs 6
I am 3 working at jobs 7
I am 3 working at jobs 8
I am 3 working at jobs 9
I am 1 working at jobs 2
I am 2 working at jobs 3

  

你会发现,第三个工人做了9件工作里面的7件,剩余两个工人闲下来了。经过代码的分析发现,这个例子的逻辑是,先将9件工作全部放在jobs通道中,然后再由工人从jobs通道里取任务,做完后返回结果。但是如果某个工人做的快,还没等剩余的工人取任务时候就完成了,那他就会做很多工作,如果在实际开发中,不考虑类似问题的话,会造成性能浪费,任务分配不平均的问题

 

经过思考,我决定改变任务分配方式,不能一股脑的将任务全部分配下去,应该做完一件,再分配一件,这样来避免任务分配问题,我在代码中,增加了一个isTrue通道,当第一个任务做完后,将结果发送给isTrue通道,然后任务分配方拿到isTrue里的值后再分配下一个任务,改造后的代码如下:

 

package main

import "fmt"

func worker(id int, jobs <-chan int, results chan<- int, isTrue chan<- bool) {
	for j := range jobs {
		fmt.Printf("I am %d working at jobs %d\n", id, j)
		results <- j * 2
		isTrue <- true
	}
}

func main() {
	jobs := make(chan int, 10)
	results := make(chan int, 10)
	isTrue := make(chan bool)
	for i := 1; i < 4; i++ {
		go worker(i, jobs, results, isTrue)
	}
	for k := 1; k < 10; k++ {
		jobs <- k
		<-isTrue
	}
	for v := 1; v < 10; v++ {
		<-results
	}
}

  

代码运行结果如下:

I am 3 working at jobs 1
I am 1 working at jobs 2
I am 2 working at jobs 3
I am 3 working at jobs 4
I am 1 working at jobs 5
I am 2 working at jobs 6
I am 3 working at jobs 7
I am 1 working at jobs 8
I am 2 working at jobs 9

  

以上就解决了任务分配问题。当然,我这种方式还是有缺点的,因为增加了分配任务的时间,会让任务完成总时间增大,在实际业务中,肯定还会有更加完美的解决方案

posted @ 2018-04-17 00:11  Joestar  阅读(314)  评论(0编辑  收藏  举报