Skip to content

Instantly share code, notes, and snippets.

@mche
Last active January 9, 2022 15:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mche/a0d3ad3597f06b54c0ec73cd5375afc0 to your computer and use it in GitHub Desktop.
Save mche/a0d3ad3597f06b54c0ec73cd5375afc0 to your computer and use it in GitHub Desktop.
Пример. Повторить один запрос несколько раз, повторить конкурентно.
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