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 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?