P
P
Pryby2021-03-24 10:38:24
go
Pryby, 2021-03-24 10:38:24

How to properly set up a channel in Golang?

Please tell me where to fix it here, so that in the end my functions would wait for each other, main ends and the maps do not have time to fill up

package main

import (
    "flag"
    "fmt"
    "log"
    "net/http"
    "strings"
    "time"
)

type inputDataStruct struct {
    url           []string
    count         int
    timeOut       int
    dataResponses map[string][]float64
    noResponses   map[string]int
}

func getResponse(urlChan chan string, inputData inputDataStruct) {
    url := <-urlChan
    start := time.Now()
    client := http.Client{
        Timeout: time.Duration(inputData.timeOut) * time.Second,
    }
    result, err := client.Get(url)
    if err != nil {
        inputData.noResponses[url] = inputData.noResponses[url] + 1
        log.Fatal(err)
    }
    elapsed := time.Since(start).Seconds()
    defer result.Body.Close()
    s := fmt.Sprintf("%s %f", url, elapsed)
    log.Println(s)
    if result.StatusCode == http.StatusOK {
        go appendResponse(urlChan, elapsed, inputData)
        urlChan <- url
    }
}

func appendResponse(urlChan chan string, time float64, inputData inputDataStruct) {
    inputData.dataResponses[<-urlChan] = append(inputData.dataResponses[<-urlChan], time)
}

func httpRequest(waitChan chan struct{}, inputData inputDataStruct) {
    //url := <- urlChan
    defer close(waitChan)
    urlChan := make(chan string)
    count := inputData.count
    j := 0
    for i := range inputData.url {
        for j < count {
            go getResponse(urlChan, inputData)
            urlChan <- inputData.url[i]
            j++
        }
        j = 0
    }

}

func parseArgument(item string) []string {
    return strings.Split(item, ",")
}
func findMinMaxAvg(values []float64) (min float64, max float64, avg float64) {
    if len(values) == 0 {
        return 0, 0, 0
    }

    min = values[0]
    max = values[0]
    var sum float64 = 0
    for _, v := range values {
        if v < min {
            min = v
        }
        if v > max {
            max = v
        }
        sum = sum + v
    }
    var count = float64(len(values))
    avg = sum / count
    return min, max, avg
}

func printMinMaxAvg(dataResponses map[string][]float64) {
    for key, _ := range dataResponses {
        min, max, avg := findMinMaxAvg(dataResponses[key])
        fmt.Printf("url: %s, min: %f, max: %f, avg: %f \n", key, min, max, avg)

    }
}

func main() {
    //urlArrChan := make(chan []string)
    waitChan := make(chan struct{})
    //var dataResponses = map[string][]float64{}
    //var noResponses = map[string]int{}
    url := flag.String("url", "", "url.")
    count := flag.Int("count", 1, "count response.")
    timeout := flag.Int("timeout", 1, "count response.")
    flag.Parse()
    var inputData inputDataStruct
    inputData.count = *count
    inputData.timeOut = *timeout
    inputData.dataResponses = map[string][]float64{}
    inputData.noResponses = map[string]int{}
    //inputData.urlChan = make(chan string)
    //inputData.syncChan = make(chan struct{})
    inputData.url = parseArgument(*url)
    //inputValue := parseArgument(*url)
    start := time.Now()
    //i := 0
    go httpRequest(waitChan, inputData)
    //urlArrChan <- inputValue
    <-waitChan
    //for i := range inputValue {
    //  //fmt.Print(inputValue[i])
    //  inputData.url = inputValue[i]
    //  httpRequest(inputData)
    //  //urlChan<-inputValue[i]
    //  i++
    //}
    elapsed := time.Since(start).Seconds()
    //<-inputData.urlChan
    //time.Sleep(1 * time.Second)
    fmt.Println(inputData.dataResponses)
    printMinMaxAvg(inputData.dataResponses)
    fmt.Printf("Total time: %f \n", elapsed)
    fmt.Println(inputData.noResponses)
    fmt.Scanln()
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
V
Vladislav, 2021-03-24
@Pryby

You need to add sync.WaitGroup inside the httpRequest function. It will look
something like this:

func httpRequest(waitChan chan struct{}, inputData inputDataStruct) {
    //url := <- urlChan
    defer close(waitChan)
    urlChan := make(chan string)
    count := inputData.count
    j := 0
    var wg sync.WaitGroup
    for i := range inputData.url {
        for j < count {
            wg.Add(1)
            go func() {
getResponse(urlChan, inputData)
wg.Done()
}
            urlChan <- inputData.url[i]
            j++
        }
        j = 0
    }
wg.Wait()
}

Of course, I'm not sure that your code will become working after that, since you have goroutines running there, for example appendResponse(), but it's not clear why.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question