dqlb38410 2018-10-31 20:48
浏览 36
已采纳

有人可以解释使用通道的Go代码块吗? 我不知道它一次执行500次动作的方式

I was looking up knowledge on how to perform a lot of HTTP requests efficiently, and I came across this answer: https://stackoverflow.com/a/23319730/749851 with this code:

package main

import (
    "flag"
    "fmt"
    "log"
    "net/http"
    "runtime"
    "time"
)

var (
    reqs int
    max  int
)

func init() {
    flag.IntVar(&reqs, "reqs", 1000000, "Total requests")
    flag.IntVar(&max, "concurrent", 200, "Maximum concurrent requests")
}

type Response struct {
    *http.Response
    err error
}

// Dispatcher
func dispatcher(reqChan chan *http.Request) {
    defer close(reqChan)
    for i := 0; i < reqs; i++ {
        req, err := http.NewRequest("GET", "http://localhost/", nil)
        if err != nil {
            log.Println(err)
        }
        reqChan <- req
    }
}

// Worker Pool
func workerPool(reqChan chan *http.Request, respChan chan Response) {
    t := &http.Transport{}
    for i := 0; i < max; i++ {
        go worker(t, reqChan, respChan)
    }
}

// Worker
func worker(t *http.Transport, reqChan chan *http.Request, respChan chan Response) {
    for req := range reqChan {
        resp, err := t.RoundTrip(req)
        r := Response{resp, err}
        respChan <- r
    }
}

// Consumer
func consumer(respChan chan Response) (int64, int64) {
    var (
        conns int64
        size  int64
    )
    for conns < int64(reqs) {
        select {
        case r, ok := <-respChan:
            if ok {
                if r.err != nil {
                    log.Println(r.err)
                } else {
                    size += r.ContentLength
                    if err := r.Body.Close(); err != nil {
                        log.Println(r.err)
                    }
                }
                conns++
            }
        }
    }
    return conns, size
}

func main() {
    flag.Parse()
    runtime.GOMAXPROCS(runtime.NumCPU())
    reqChan := make(chan *http.Request)
    respChan := make(chan Response)
    start := time.Now()
    go dispatcher(reqChan)
    go workerPool(reqChan, respChan)
    conns, size := consumer(respChan)
    took := time.Since(start)
    ns := took.Nanoseconds()
    av := ns / conns
    average, err := time.ParseDuration(fmt.Sprintf("%d", av) + "ns")
    if err != nil {
        log.Println(err)
    }
    fmt.Printf("Connections:\t%d
Concurrent:\t%d
Total size:\t%d bytes
Total time:\t%s
Average time:\t%s
", conns, max, size, took, average)
}

I'm coming from node so I don't really understand this "go" code.

What part of it is limiting it to 500 HTTP actions at a time? And is it operating in chunks of 500, waiting until that chunk of 500 is finished then starting a new 500, OR is it just always chugging along adding 1 more once it hits 499, etc.

I see that the "workerPool" func goes over a loop only as many times as the maximum amount of concurrent requests, calling "worker" 500 times, but how does it do the next 500 or even the whole 1 million eventually?

  • 写回答

1条回答 默认 最新

  • dto52236 2018-10-31 21:20
    关注

    It isn’t 500, it is 200, and the magic line is:

    for i := 0; i < max; i++ {
        go worker(t, reqChan, respChan)
    }
    

    max defaults to 200; and may be over ridden with a command line switch. Each of these “go routines”, which are akin to ridiculously lightweight threads, initializes itself then waits for channel input. This is where the magic occurs - when a request comes in, it results in sending on a channel. There are max (200) go-routines receiving from this channel, and the channel is unbuffered, therefore up to 200 requests can be inflight. The 201th would cause the sender to wait until one of the workers completed and invoked the receive (<-) op.

    The subtlety of Go’s message passing deserves far better, and a bit of googling around will uncover well written essays, tutorials and examples of concurrency in Go.

    Good luck with Go; I think it is a wonderful language. It is elegant, expressive and concise. You might never be able to stomach c++ or java again....

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 关于大棚监测的pcb板设计
  • ¥15 stm32开发clion时遇到的编译问题
  • ¥15 lna设计 源简并电感型共源放大器
  • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用
  • ¥15 C++ yoloV5改写遇到的问题
  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥15 帮我写一个c++工程