大佬们go并发有个问题想请教一下-关于1秒钟并发请求N个api的问题

xiaolaodi · · 1582 次点击
我理解,楼主的意思大概如下。 有100条原始条件,然后可以造出10000条请求,请求server的时候,需要控制并发,不能超过10条/秒。 我觉得,最简单的建模就是(假设goN是一个go程): ``` go1 readCondition -> chan *Contidion go2 chan *Condition -> buildRequest -> chan *Request go3 chan *Request -> sleepAndDoRequest() ``` 代码大概如下(代码未经调试,不保证bug free,但思路基本清楚): ```go package main import ( "fmt" "io/ioutil" "log" "net/http" "net/url" "runtime" "sync" "time" ) type Condition struct { Start int End int BaseSetting string } func readContidion(conditions chan <- *Condition) { for i:= 0; i<100; i ++ { c := &Condition{ Start:i, End:i+1, } conditions <- c } } func buildRequest(conditions <- chan *Condition, reqs chan <- *http.Request ) { for c := range conditions { for i := c.Start; i < c.End; i++ { rawURL := fmt.Sprintf("http://www.baidu.com?s=xx&i=%v", i) u, _ := url.Parse(rawURL) req := &http.Request{ URL: u, } reqs <- req } } } func doRequest(reqs <- chan *http.Request ,wg *sync.WaitGroup) { wg.Add(1) defer wg.Done() t := time.NewTicker(time.Second / 10) for { select { case <- t.C: req := <- reqs wg.Add(1) go func() { // 用go保证不阻塞doRequest,控制并发 defer wg.Done() c := &http.Client{} resp, err := c.Do(req) if err != nil { defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) log.Printf("resp body = %s\n", body) } else { log.Println(err) } }() } } } func main() { log.SetFlags(log.LstdFlags) conditions := make(chan *Condition, 5) requests := make(chan *http.Request, 5) wg := &sync.WaitGroup{} // 用wg保证go程不会因为主go程退出而退出 go doRequest(requests, wg) // 先启动,保证wg一定已经被.Add runtime.Gosched() go readContidion(conditions) go buildRequest(conditions, requests) wg.Wait() } ``` 后续的改进点,实际BuildCondition这块逻辑,如果可以确认速度够快,无需独立使用go程,可以和buildReq合并到一处,最终写 `*req` 作为一个分割点。 ``` go1 readContidion->buildReq go2 readReq -> go doReq() ```
#12
更多评论
用go 协程去请求api
#1
哥们 我也这么想的,但是似乎不对。
#2