有人可以解释这个使用通道的 Go 代码块吗?我不明白它是如何一次做 500 个动作的



我在查找如何高效执行大量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%dnConcurrent:t%dnTotal size:t%d bytesnTotal time:t%snAverage time:t%sn", conns, max, size, took, average)
}

我来自node,所以我并不真正理解这个"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)
}

max默认为200;并且可以使用命令行开关来过度使用。每一个类似于轻量级线程的"go例程"都会初始化自己,然后等待通道输入。这就是魔法发生的地方——当请求进来时,它会导致在通道上发送。从该信道接收的最多(200(个go例程,并且该信道是无缓冲的,因此最多可以有200个请求。第201次将导致发送者等待,直到其中一个工作者完成并调用接收(<-(操作。

围棋传递信息的微妙之处值得改进,在谷歌上搜索一下,就会发现写得很好的文章、教程和围棋并发的例子。

祝围棋好运;我认为这是一种很棒的语言。它优雅、富有表现力、简洁。你可能再也无法忍受c++或java了。。。。

最新更新