可以很轻松的实现一个带缓冲的通道 (可以参见 14.2.5 章节),它的容量是并发请求的最大数目。下面的示例 max_tasks.go 没做任何事情,它包含了下列技巧:不超过 MAXREQS 的请求将被处理并且是同时处理,因为当通道 sem 的缓冲区全被占用时,函数 handle 被阻塞,直到缓冲区中的请求被执行完成并且从 sem 中删除之前,不能执行其他的请求。sem 就像一个 semaphore (信号量),表示一个在一定条件的程序中的一个标志变量的技术术语:由此得名。

    Listing 14.16—max_tasks.go:

    1. package main
    2. const (
    3. AvailableMemory = 10 << 20
    4. // 10 MB, 示例
    5. AverageMemoryPerRequest = 10 << 10
    6. // 10 KB
    7. MAXREQS = AvailableMemory / AverageMemoryPerRequest
    8. // 原文中说 MAXREQS 是 1000,实际计算是 1024 ,后面按照原文的 1000 来描述
    9. )
    10. var sem = make(chan int, MAXREQS)
    11. type Request struct {
    12. a, b int
    13. replyc chan int
    14. }
    15. func process(r *Request) {
    16. // Do something 做任何事
    17. // 可能需要很长时间并使用大量内存或CPU
    18. }
    19. func handle(r *Request) {
    20. process(r)
    21. // 信号完成:开始启用下一个请求
    22. // 将 sem 的缓冲区释放一个位置
    23. <-sem
    24. }
    25. func Server(queue chan *Request) {
    26. for {
    27. sem <- 1
    28. // 当通道已满(1000 个请求被激活)的时候将被阻塞
    29. // 所以停在这里等待,直到 sem 有容量(被释放),才能继续去处理请求
    30. // (doesn’t matter what we put in it)
    31. request := <-queue
    32. go handle(request)
    33. }
    34. }
    35. func main() {
    36. queue := make(chan *Request)
    37. go Server(queue)
    38. }

    通过这种方式,程序中的协程通过使用缓冲通道(这个通道作为一个 semaphore 被使用)来调整资源的使用,实现了对内存等有限资源的优化。