go语言使用goroutines
和channel
实现一个工作池相当简单。使用goroutines
开指定书目线程,通道分别传递任务和任务结果。简单的线程池代码如下:
1 package main 2 3 import "fmt" 4 import "time" 5 6 // Here's the worker, of which we'll run several 7 // concurrent instances. These workers will receive 8 // work on the `jobs` channel and send the corresponding 9 // results on `results`. We'll sleep a second per job to10 // simulate an expensive task.11 func worker(id int, jobs <-chan int, results chan<- int) {12 for j := range jobs {13 fmt.Println("worker", id, "started job", j)14 time.Sleep(time.Second)15 fmt.Println("worker", id, "finished job", j)16 results <- j * 217 }18 }19 20 func main() {21 22 // In order to use our pool of workers we need to send23 // them work and collect their results. We make 224 // channels for this.25 jobs := make(chan int, 100)26 results := make(chan int, 100)27 28 // This starts up 3 workers, initially blocked29 // because there are no jobs yet.30 for w := 1; w <= 3; w++ {31 go worker(w, jobs, results)32 }33 34 // Here we send 5 `jobs` and then `close` that35 // channel to indicate that's all the work we have.36 for j := 1; j <= 5; j++ {37 jobs <- j38 }39 close(jobs)40 41 // Finally we collect all the results of the work.42 for a := 1; a <= 5; a++ {43 <-results44 }45 }
执行上面代码,将得到以下输出结果
1 worker 3 started job 2 2 worker 1 started job 1 3 worker 2 started job 3 4 worker 3 finished job 2 5 worker 3 started job 4 6 worker 1 finished job 1 7 worker 1 started job 5 8 worker 2 finished job 3 9 worker 3 finished job 410 worker 1 finished job 5
看代码中注释也大概能理解每一步的含义,代码25行和26行分别初始化了2个通道,用于发送任务给子线程和接收子线程计算的任务结果。30-32行代码是启动了3个子线程,用于处理任务,并将任务通道和结果通道传递给了线程函数。36-38行代码是发送任务到jobs通道,工作线程在没有任务时,是阻塞着等待任务,当发现任务通道中有任务时,开始执行任务,当任务执行完毕时,将任务结果发送给结果通道。
jobs <-chan int:只能接收数据
results chan<- int:只能发送数据