Last active
January 9, 2022 15:40
-
-
Save mche/a0d3ad3597f06b54c0ec73cd5375afc0 to your computer and use it in GitHub Desktop.
Пример. Повторить один запрос несколько раз, повторить конкурентно.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"net/http" | |
"log" | |
"time" | |
"context" | |
"net" | |
"io/ioutil" | |
) | |
var ( | |
request *http.Request | |
err error | |
client *http.Client = &http.Client{} | |
///client := http.DefaultClient | |
timeout1 time.Duration = 500 * time.Millisecond | |
concurrency = 9 | |
total = 57 | |
) | |
func init() { | |
request, err = http.NewRequest("GET", "http://httpbin.org/get?foo=bar&я=45", nil) | |
if err != nil { | |
log.Fatalf("%v", err) | |
} | |
} | |
type result struct { | |
cnt int | |
resp http.Response | |
err error | |
tm time.Duration | |
} | |
// getResults sends requests in parallel but only up to a certain | |
// limit, and furthermore it's only parallel up to the amount of CPUs but | |
// is always concurrent up to the concurrency limit | |
func getResults(concurrencyLimit int, total int) []result { | |
// this buffered channel will block at the concurrency limit | |
semaphoreChan := make(chan bool, concurrencyLimit) | |
// this channel will not block and collect the http request results | |
resultsChan := make(chan *result) | |
defer func() { | |
close(semaphoreChan) | |
close(resultsChan) | |
}() | |
for i := 0; i < total; i++ { | |
go goRequest(1, resultsChan, semaphoreChan) | |
} | |
var results []result | |
sum := 0 | |
for res := range resultsChan { | |
if res.resp.StatusCode == 200 { | |
results = append(results, *res) | |
fmt.Printf("[%v] %v took %v\n", res.cnt, res.resp.StatusCode, res.tm) | |
sum += res.cnt | |
if len(results) == total { | |
break | |
} /*else { | |
go goRequest(1, resultsChan) | |
}*/ | |
} else { | |
///log.Printf("again Request %v", res.cnt) | |
go goRequest(res.cnt+1, resultsChan, semaphoreChan) | |
} | |
} | |
log.Printf("done all results on %v requests", sum) | |
return results | |
} | |
func goRequest(i int, resultsChan chan *result, semaphoreChan chan bool) { | |
semaphoreChan <- true | |
ctx, cancel := context.WithTimeout(request.Context(), timeout1) | |
defer cancel() | |
req := request.WithContext(ctx) | |
start := time.Now() | |
resp, err := client.Do(req) | |
if e,ok := err.(net.Error); ok && e.Timeout() { | |
log.Printf("Do request timeout: %s\n", err) | |
resultsChan <- &result{cnt: i} | |
} else if err != nil { | |
log.Panicf("Cannot do request: %s\n", err) | |
} else { | |
defer resp.Body.Close() | |
body, err := ioutil.ReadAll(resp.Body) | |
log.Printf("body: %T %v\n", body, len(body)) | |
resultsChan <- &result{i, *resp, err, time.Since(start)} | |
} | |
<- semaphoreChan | |
} | |
func main() { | |
startTime := time.Now() | |
results := getResults(concurrency, total) | |
log.Printf("%d concurrent requests: %d/%d in %v", concurrency, len(results), total, time.Since(startTime).Seconds()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment