登录
首页 >  Golang >  Go问答

解释下这段使用 Go 通道的代码如何同时执行500个操作

来源:stackoverflow

时间:2024-03-12 13:03:27 394浏览 收藏

目前golang学习网上已经有很多关于Golang的文章了,自己在初次阅读这些文章中,也见识到了很多学习思路;那么本文《解释下这段使用 Go 通道的代码如何同时执行500个操作》,也希望能帮助到大家,如果阅读完后真的对你学习Golang有帮助,欢迎动动手指,评论留言并分享~

问题内容

我正在查找有关如何有效执行大量 http 请求的知识,我发现了这个答案:https://stackoverflow.com/a/23319730/749851,其中包含以下代码:

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\nConcurrent:\t%d\nTotal size:\t%d bytes\nTotal time:\t%s\nAverage time:\t%s\n", conns, max, size, took, average)
}

我来自节点,所以我不太理解这个“go”代码。

它的哪一部分将其限制为一次 500 个 http 操作?它是否以 500 块为一组进行操作,等待 500 块完成,然后开始新的 500 块,或者它总是在达到 499 块时再加 1 块,等等。

我发现“workerpool”函数的循环次数与最大并发请求数相同,调用“worker”500 次,但它最终如何执行接下来的 500 次甚至整个 100 万次?


解决方案


不是 500,而是 200,神奇的线条是:

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

最大默认为200;并且可以用命令行开关覆盖。 这些“go 例程”中的每一个都类似于极其轻量级的线程,初始化自身然后等待通道输入。这就是神奇发生的地方 - 当请求进来时,它会导致在通道上发送。最多有 (200) 个 go 例程从该通道接收,并且该通道是无缓冲的,因此最多可以处理 200 个请求。第 201 个将导致发送方等待,直到其中一个工作人员完成并调用接收 (<-) 操作。

go 消息传递的微妙之处值得更好,并且稍微谷歌一下就会发现写得很好的文章、教程和 go 中并发的示例。

祝 go 好运;我认为这是一门美妙的语言。它优雅、富有表现力、简洁。你可能再也无法忍受 c++ 或 java...

文中关于的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《解释下这段使用 Go 通道的代码如何同时执行500个操作》文章吧,也可关注golang学习网公众号了解相关技术文章。

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>