使用Golang的一个简单的工作者和工作队列的例子

169 阅读2分钟

在这个例子中,我们将创建一个 "缓冲 "通道,其容量最多为11个资源槽。如果超过11个作业,它会拒绝它们。我们将只有一个工作者/goroutine在运行,以便处理作业。应用程序将阻塞,直到所有工作完成,所以没有工作丢失。

改进措施

虽然这是一个 "基本 "的例子,但必须考虑一些额外的功能,例如:

  • 终止长期运行的作业。

  • 运行多个工作者。

  • 防止通道接受更多的作业,同时优雅地停止工作者。

  • 杀死所有工作者。

例子

这里也有一个很好的例子:

package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

var (
	// wg is used to force the application wait for all goroutines to finish before exiting.
	wg sync.WaitGroup
	// jobChan is a buffered channel that has the capacity of maximum 11 resource slot.
	jobChan = make(chan int, 11)
	// waiters is used to make goroutines sleep in order to simulate time it took to process the job.
	waiters = []int{0, 1, 2, 3, 4}
)

func main() {
	rand.Seed(time.Now().UnixNano())

	fmt.Println("BEGIN")

	// Tell how many worker you will be running.
	wg.Add(1)

	// Run 1 worker to handle jobs.
	go worker(jobChan, &wg)

	// Send 10 jobs to job channel.
	for i := 1; i <= 10; i++ {
		if !queueJob(i, jobChan) {
			fmt.Println("Channel is full... Service unavailable...")
		}
	}

	// Close the job channel.
	close(jobChan)

	// Block exiting until all the goroutines are finished.
	wg.Wait()

	fmt.Println("END")
}

// queueJob puts job into channel. If channel buffer is full, return false.
func queueJob(job int, jobChan chan<- int) bool {
	select {
	case jobChan <- job:
		return true
	default:
		return false
	}
}

// worker processes jobs.
func worker(jobChan <-chan int, wg *sync.WaitGroup) {
	// As soon as the current goroutine finishes (job done!), notify back WaitGroup.
	defer wg.Done()

	fmt.Println("Worker is waiting for jobs")

	for job := range jobChan {
		fmt.Println("Worker picked job", job)

		wait := time.Duration(rand.Intn(len(waiters)))
		time.Sleep(wait * time.Second)

		// Process the job ...

		fmt.Println("Worker completed job", job, "in", int(wait), "second(s)")
	}
}

测试

BEGIN
Worker is waiting for jobs
Worker picked job 1
Worker completed job 1 in 4 second(s)
Worker picked job 2
Worker completed job 2 in 1 second(s)
Worker picked job 3
Worker completed job 3 in 4 second(s)
Worker picked job 4
Worker completed job 4 in 3 second(s)
Worker picked job 5
Worker completed job 5 in 2 second(s)
Worker picked job 6
Worker completed job 6 in 1 second(s)
Worker picked job 7
Worker completed job 7 in 1 second(s)
Worker picked job 8
Worker completed job 8 in 2 second(s)
Worker picked job 9
Worker completed job 9 in 1 second(s)
Worker picked job 10
Worker completed job 10 in 2 second(s)
END

如果作业量超过通道的限制,你会看到一些作业被拒绝。例如,如果你发送15个作业到限制为11个作业的通道,你应该看到类似下面的情况,有4个作业被拒绝:

BEGIN
Channel is full... Service unavailable...
Channel is full... Service unavailable...
Channel is full... Service unavailable...
Channel is full... Service unavailable...
...
...