有人可以解释这个使用通道的 Go 代码块吗?我不明白它是如何一次执行 500 个动作的
Could someone explain this block of Go code that uses channels? I don't understand how it's doing 500 actions at a time
我正在查找有关如何有效执行大量 HTTP 请求的知识,然后我遇到了这个答案: 使用以下代码:
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)
}
我来自 node,所以我不太理解这段 "go" 代码。
它的哪一部分将它限制为一次 500 个 HTTP 操作?它是以 500 块为单位运行,等到 500 块完成然后开始一个新的 500,还是它总是在达到 499 时再添加 1,等等
我看到 "workerPool" func 循环次数仅与最大并发请求数一样多,调用 "worker" 500 次,但接下来的 500 次甚至它是如何进行的最终整整一百万?
不是500,是200,魔法线是:
for i := 0; i < max; i++ {
go worker(t, reqChan, respChan)
}
最大值默认为200;并且可能会被命令行开关淹没。
这些类似于可笑的轻量级线程的“go routines”中的每一个都会初始化自身,然后等待通道输入。这就是魔法发生的地方——当一个请求进来时,它会导致在一个通道上发送。从该通道接收最多 (200) 个 go-routines,并且该通道是无缓冲的,因此最多可以处理 200 个请求。第 201 个将导致发送方等待,直到其中一名工作人员完成并调用接收 (<-) 操作。
Go 消息传递的微妙之处值得更好的理解,稍微谷歌一下就会发现写得很好的论文、教程和 Go 并发示例。
祝你 Go 好运;我认为这是一种美妙的语言。它优雅、富有表现力且简洁。您可能再也无法忍受 C++ 或 java....
我正在查找有关如何有效执行大量 HTTP 请求的知识,然后我遇到了这个答案: 使用以下代码:
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)
}
我来自 node,所以我不太理解这段 "go" 代码。
它的哪一部分将它限制为一次 500 个 HTTP 操作?它是以 500 块为单位运行,等到 500 块完成然后开始一个新的 500,还是它总是在达到 499 时再添加 1,等等
我看到 "workerPool" func 循环次数仅与最大并发请求数一样多,调用 "worker" 500 次,但接下来的 500 次甚至它是如何进行的最终整整一百万?
不是500,是200,魔法线是:
for i := 0; i < max; i++ {
go worker(t, reqChan, respChan)
}
最大值默认为200;并且可能会被命令行开关淹没。 这些类似于可笑的轻量级线程的“go routines”中的每一个都会初始化自身,然后等待通道输入。这就是魔法发生的地方——当一个请求进来时,它会导致在一个通道上发送。从该通道接收最多 (200) 个 go-routines,并且该通道是无缓冲的,因此最多可以处理 200 个请求。第 201 个将导致发送方等待,直到其中一名工作人员完成并调用接收 (<-) 操作。
Go 消息传递的微妙之处值得更好的理解,稍微谷歌一下就会发现写得很好的论文、教程和 Go 并发示例。
祝你 Go 好运;我认为这是一种美妙的语言。它优雅、富有表现力且简洁。您可能再也无法忍受 C++ 或 java....