Golang HTTP requestsHandling HTTP requestsHTTP Client requests done rightRetry loop for asynchronous HTTP requestsGolang HTTP status checkerUnit testing HTTP requestsProxying Socket.io requests and other HTTP requestsGolang Tour Web Crawler ExerciseGolang HTTP request retry codeRepeatable HTTP requests in PythonMaking multiple HTTP requests to Twitter

How to write Quadratic equation with negative coefficient

What does "tick" mean in this sentence?

Would a primitive species be able to learn English from reading books alone?

Why is the sun approximated as a black body at ~ 5800 K?

Would this string work as string?

If the only attacker is removed from combat, is a creature still counted as having attacked this turn?

Giving feedback to someone without sounding prejudiced

In One Punch Man, is King actually weak?

El Dorado Word Puzzle II: Videogame Edition

Animation: customize bounce interpolation

If A is dense in Q, then it must be dense in R.

How to preserve electronics (computers, iPads and phones) for hundreds of years

Showing mass murder in a kid's book

Review your own paper in Mathematics

Do I have to take mana from my deck or hand when tapping a dual land?

Has the laser at Magurele, Romania reached a tenth of the Sun's power?

How do you justify more code being written by following clean code practices?

Are Captain Marvel's powers affected by Thanos breaking the Tesseract and claiming the stone?

SOQL query causes internal Salesforce error

Determining multivariate least squares with constraint

Why do Radio Buttons not fill the entire outer circle?

Why does a 97 / 92 key piano exist by Bösendorfer?

I'm just a whisper. Who am I?

How to get directions in deep space?



Golang HTTP requests


Handling HTTP requestsHTTP Client requests done rightRetry loop for asynchronous HTTP requestsGolang HTTP status checkerUnit testing HTTP requestsProxying Socket.io requests and other HTTP requestsGolang Tour Web Crawler ExerciseGolang HTTP request retry codeRepeatable HTTP requests in PythonMaking multiple HTTP requests to Twitter













1












$begingroup$


I'm beginning to learn about Golang and I would like to have some advice about the following program.



package main

import (
"fmt"
"net/http"
"time"
)

const BenchmarkTry = 1000

type PageBenchmark struct
url string
time int64 // microseconds


func execBenchmark(url string, channel chan PageBenchmark)
totalExecTimeChan := make(chan int64, BenchmarkTry) // set size to prevent blocked goroutine
totalExecTime := int64(0)

// start all the goroutines
for i := 0; i < BenchmarkTry; i++
go execHttpRequest(url, totalExecTimeChan)


// catch new values from totalExecTimeChan values come from execHttpRequest()) and add it to the total
for i := 0; i < BenchmarkTry; i++
totalExecTime += <-totalExecTimeChan // waiting to get a value from one of the goroutines started in the previous for loop


channel <- PageBenchmarkurl, totalExecTime / BenchmarkTry


// exec http request and attach exec time to channel
func execHttpRequest(url string, channel chan int64)
begin := time.Now()
_, _ = http.Get(url)
channel <- time.Since(begin).Nanoseconds() / 1000000 // convert to milliseconds


func main()
sites := [...]string



pages := [...]string



benchmarkChan := make(chan PageBenchmark, len(sites)*len(pages)) // set size to prevent blocked goroutine

begin := time.Now()
fmt.Println("Beginning !")

// start all the goroutines
for site := range sites
for page := range pages
go execBenchmark(sites[site]+pages[page], benchmarkChan)



// catch new values from benchmarkChan and "print" the PageBenchmark
for i := 0; i < len(sites)*len(pages); i++
benchmark := <-benchmarkChan
fmt.Printf("Url : %vnResponse Time : %d msnn", benchmark.url, benchmark.time)


// print execution time
fmt.Println("End.")
fmt.Println(fmt.Sprintf("%d ms", time.Since(begin).Nanoseconds()/1000000))




Basically, I'm making HTTP requests (GET method) to multiple URLs on multiple web sites. 1000 requests by URL in this example.



For now, I just want to start some goroutines in this order:



  1. Main: start a benchmark (goroutine) for each web site pages, get the average execution time and print it.


  2. Page routine: start 1000 goroutines (benchmark tries), get the execution times from a channel and store the average execution time in an other channel.


  3. Execute an HTTP request on the page and store the execution time in a channel.


This piece of code works but there may be things I'm missing.



  • Is the execution scheduling valid?

  • Is it appropriate to use defined size channels here?

  • Is there a better/more effective way to achieve this task?









share|improve this question









New contributor




hunomina is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$
















    1












    $begingroup$


    I'm beginning to learn about Golang and I would like to have some advice about the following program.



    package main

    import (
    "fmt"
    "net/http"
    "time"
    )

    const BenchmarkTry = 1000

    type PageBenchmark struct
    url string
    time int64 // microseconds


    func execBenchmark(url string, channel chan PageBenchmark)
    totalExecTimeChan := make(chan int64, BenchmarkTry) // set size to prevent blocked goroutine
    totalExecTime := int64(0)

    // start all the goroutines
    for i := 0; i < BenchmarkTry; i++
    go execHttpRequest(url, totalExecTimeChan)


    // catch new values from totalExecTimeChan values come from execHttpRequest()) and add it to the total
    for i := 0; i < BenchmarkTry; i++
    totalExecTime += <-totalExecTimeChan // waiting to get a value from one of the goroutines started in the previous for loop


    channel <- PageBenchmarkurl, totalExecTime / BenchmarkTry


    // exec http request and attach exec time to channel
    func execHttpRequest(url string, channel chan int64)
    begin := time.Now()
    _, _ = http.Get(url)
    channel <- time.Since(begin).Nanoseconds() / 1000000 // convert to milliseconds


    func main()
    sites := [...]string



    pages := [...]string



    benchmarkChan := make(chan PageBenchmark, len(sites)*len(pages)) // set size to prevent blocked goroutine

    begin := time.Now()
    fmt.Println("Beginning !")

    // start all the goroutines
    for site := range sites
    for page := range pages
    go execBenchmark(sites[site]+pages[page], benchmarkChan)



    // catch new values from benchmarkChan and "print" the PageBenchmark
    for i := 0; i < len(sites)*len(pages); i++
    benchmark := <-benchmarkChan
    fmt.Printf("Url : %vnResponse Time : %d msnn", benchmark.url, benchmark.time)


    // print execution time
    fmt.Println("End.")
    fmt.Println(fmt.Sprintf("%d ms", time.Since(begin).Nanoseconds()/1000000))




    Basically, I'm making HTTP requests (GET method) to multiple URLs on multiple web sites. 1000 requests by URL in this example.



    For now, I just want to start some goroutines in this order:



    1. Main: start a benchmark (goroutine) for each web site pages, get the average execution time and print it.


    2. Page routine: start 1000 goroutines (benchmark tries), get the execution times from a channel and store the average execution time in an other channel.


    3. Execute an HTTP request on the page and store the execution time in a channel.


    This piece of code works but there may be things I'm missing.



    • Is the execution scheduling valid?

    • Is it appropriate to use defined size channels here?

    • Is there a better/more effective way to achieve this task?









    share|improve this question









    New contributor




    hunomina is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.







    $endgroup$














      1












      1








      1





      $begingroup$


      I'm beginning to learn about Golang and I would like to have some advice about the following program.



      package main

      import (
      "fmt"
      "net/http"
      "time"
      )

      const BenchmarkTry = 1000

      type PageBenchmark struct
      url string
      time int64 // microseconds


      func execBenchmark(url string, channel chan PageBenchmark)
      totalExecTimeChan := make(chan int64, BenchmarkTry) // set size to prevent blocked goroutine
      totalExecTime := int64(0)

      // start all the goroutines
      for i := 0; i < BenchmarkTry; i++
      go execHttpRequest(url, totalExecTimeChan)


      // catch new values from totalExecTimeChan values come from execHttpRequest()) and add it to the total
      for i := 0; i < BenchmarkTry; i++
      totalExecTime += <-totalExecTimeChan // waiting to get a value from one of the goroutines started in the previous for loop


      channel <- PageBenchmarkurl, totalExecTime / BenchmarkTry


      // exec http request and attach exec time to channel
      func execHttpRequest(url string, channel chan int64)
      begin := time.Now()
      _, _ = http.Get(url)
      channel <- time.Since(begin).Nanoseconds() / 1000000 // convert to milliseconds


      func main()
      sites := [...]string



      pages := [...]string



      benchmarkChan := make(chan PageBenchmark, len(sites)*len(pages)) // set size to prevent blocked goroutine

      begin := time.Now()
      fmt.Println("Beginning !")

      // start all the goroutines
      for site := range sites
      for page := range pages
      go execBenchmark(sites[site]+pages[page], benchmarkChan)



      // catch new values from benchmarkChan and "print" the PageBenchmark
      for i := 0; i < len(sites)*len(pages); i++
      benchmark := <-benchmarkChan
      fmt.Printf("Url : %vnResponse Time : %d msnn", benchmark.url, benchmark.time)


      // print execution time
      fmt.Println("End.")
      fmt.Println(fmt.Sprintf("%d ms", time.Since(begin).Nanoseconds()/1000000))




      Basically, I'm making HTTP requests (GET method) to multiple URLs on multiple web sites. 1000 requests by URL in this example.



      For now, I just want to start some goroutines in this order:



      1. Main: start a benchmark (goroutine) for each web site pages, get the average execution time and print it.


      2. Page routine: start 1000 goroutines (benchmark tries), get the execution times from a channel and store the average execution time in an other channel.


      3. Execute an HTTP request on the page and store the execution time in a channel.


      This piece of code works but there may be things I'm missing.



      • Is the execution scheduling valid?

      • Is it appropriate to use defined size channels here?

      • Is there a better/more effective way to achieve this task?









      share|improve this question









      New contributor




      hunomina is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.







      $endgroup$




      I'm beginning to learn about Golang and I would like to have some advice about the following program.



      package main

      import (
      "fmt"
      "net/http"
      "time"
      )

      const BenchmarkTry = 1000

      type PageBenchmark struct
      url string
      time int64 // microseconds


      func execBenchmark(url string, channel chan PageBenchmark)
      totalExecTimeChan := make(chan int64, BenchmarkTry) // set size to prevent blocked goroutine
      totalExecTime := int64(0)

      // start all the goroutines
      for i := 0; i < BenchmarkTry; i++
      go execHttpRequest(url, totalExecTimeChan)


      // catch new values from totalExecTimeChan values come from execHttpRequest()) and add it to the total
      for i := 0; i < BenchmarkTry; i++
      totalExecTime += <-totalExecTimeChan // waiting to get a value from one of the goroutines started in the previous for loop


      channel <- PageBenchmarkurl, totalExecTime / BenchmarkTry


      // exec http request and attach exec time to channel
      func execHttpRequest(url string, channel chan int64)
      begin := time.Now()
      _, _ = http.Get(url)
      channel <- time.Since(begin).Nanoseconds() / 1000000 // convert to milliseconds


      func main()
      sites := [...]string



      pages := [...]string



      benchmarkChan := make(chan PageBenchmark, len(sites)*len(pages)) // set size to prevent blocked goroutine

      begin := time.Now()
      fmt.Println("Beginning !")

      // start all the goroutines
      for site := range sites
      for page := range pages
      go execBenchmark(sites[site]+pages[page], benchmarkChan)



      // catch new values from benchmarkChan and "print" the PageBenchmark
      for i := 0; i < len(sites)*len(pages); i++
      benchmark := <-benchmarkChan
      fmt.Printf("Url : %vnResponse Time : %d msnn", benchmark.url, benchmark.time)


      // print execution time
      fmt.Println("End.")
      fmt.Println(fmt.Sprintf("%d ms", time.Since(begin).Nanoseconds()/1000000))




      Basically, I'm making HTTP requests (GET method) to multiple URLs on multiple web sites. 1000 requests by URL in this example.



      For now, I just want to start some goroutines in this order:



      1. Main: start a benchmark (goroutine) for each web site pages, get the average execution time and print it.


      2. Page routine: start 1000 goroutines (benchmark tries), get the execution times from a channel and store the average execution time in an other channel.


      3. Execute an HTTP request on the page and store the execution time in a channel.


      This piece of code works but there may be things I'm missing.



      • Is the execution scheduling valid?

      • Is it appropriate to use defined size channels here?

      • Is there a better/more effective way to achieve this task?






      multithreading go http benchmarking






      share|improve this question









      New contributor




      hunomina is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      hunomina is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 3 mins ago









      esote

      2,78611038




      2,78611038






      New contributor




      hunomina is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 2 hours ago









      hunominahunomina

      61




      61




      New contributor




      hunomina is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      hunomina is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      hunomina is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.




















          1 Answer
          1






          active

          oldest

          votes


















          0












          $begingroup$

          When running your program with the Go race detector, it found no race conditions. That's good!



          Benchmark through testing




          Is there a better/more effective way to achieve this task?




          For benchmarking, it is recommended to use the benchmarking utilities provided by the testing package.



          A lot of this code is boilerplate benchmarking code. With the testing package you can be more confident in the accuracy of your benchmarks, especially since you're benchmarking goroutines.



          (I will leave switching to the testing package for you.)



          Performance bias



          sites[site]+pages[page]


          Adding strings through the + operator is slow. This could be biasing your results (ie if you have lots of very long strings), but that also depends on how many sites you test with.



          Without knowledge of your full usage, it's hard to tell.



          Accuracy



          time.Since(begin).Nanoseconds() / 1000000 // convert to milliseconds


          I would instead use .Seconds(). Any variation on the scale of milliseconds would be meaningless. From testing with one site and two pages, I received response times of 10288 (10s) and 8128 ms (8s) and an end time of 30073 ms (30s).



          Rather than converting to int64 I would keep the type as float64.



          String formatting



          fmt.Println("End.")
          fmt.Println(fmt.Sprintf("%d ms", time.Since(begin).Nanoseconds()/1000000))


          Should then be converted to:



          fmt.Printf("End.nTotal time: %.0fsn", time.Since(begin).Seconds())


          And, given the switch to float64



          fmt.Printf("Url : %vnResponse Time : %d msnn", benchmark.url, benchmark.time)


          Should instead be:



          fmt.Printf("Url: %snResponse Time: %.0fsnn", benchmark.url,
          benchmark.time)


          (Notice I use %s rather than %v.)



          Variable naming



          Variables can have shorter names, especially in shorter functions where their purpose is clear.




          • totalExecTimeChan becomes timeChan


          • totalExecTime becoems time


          • BenchmarkTry becomes tries

          I would argue that the names tc and t would be equally fine for the first two.



          Capitalization matters in Go. The variable BenchmarkTry and the type PageBenchmark would be exported. In this case it does not make a difference, but for larger programs and packages it would be important.



          Miscellaneous




          1. This cast is not needed.



            totalExecTime := int64(0)


            With the switch to float64, it can instead be:



            totalExecTime := 0.0


          2. Some of your comments extend beyond the 80-character column. It is useful to stay within 80 characters when viewing things split across your screen. Instead, move comments to the line before the code. (Some of these comments are superfluous, but you're learning so that's okay.)


          3. Store len(sites)*len(pages) in a constant, rather than recomputing it each time.


          Conclusion



          Here is the code I ended up with:



          package main

          import (
          "fmt"
          "net/http"
          "time"
          )

          const tries = 1000

          type pageBenchmark struct
          url string
          time float64


          func execBenchmark(url string, benchmarks chan pageBenchmark)
          // prevent blocked goroutine
          timeChan := make(chan float64, tries)
          time := 0.0

          // start all requests
          for i := 0; i < tries; i++
          go execHTTPRequest(url, timeChan)


          // catch new values from execHTTPRequest()
          for i := 0; i < tries; i++
          // wait to get value from goroutine
          time += <-timeChan


          benchmarks <- pageBenchmarkurl, time / tries


          // exec http request and attach exec time to channel
          func execHTTPRequest(url string, timeChan chan float64)
          begin := time.Now()
          _, _ = http.Get(url)
          timeChan <- time.Since(begin).Seconds()


          func main()
          sites := [...]string
          // sites


          pages := [...]string
          // pages


          const length = len(sites) * len(pages)

          // set size to prevent blocked goroutine
          benchmarks := make(chan pageBenchmark, length)

          begin := time.Now()

          fmt.Println("Beginning!n")

          // start all the goroutines
          for site := range sites
          for page := range pages
          go execBenchmark(sites[site]+pages[page], benchmarks)



          // catch and print benchmarks
          for i := 0; i < length; i++
          b := <-benchmarks
          fmt.Printf("Url: %snResponse Time: %.0fsnn", b.url, b.time)


          // print total execution time
          fmt.Printf("End.nTotal time: %.0fsn", time.Since(begin).Seconds())



          Hope this helps!





          share









          $endgroup$












            Your Answer





            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );






            hunomina is a new contributor. Be nice, and check out our Code of Conduct.









            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f215883%2fgolang-http-requests%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0












            $begingroup$

            When running your program with the Go race detector, it found no race conditions. That's good!



            Benchmark through testing




            Is there a better/more effective way to achieve this task?




            For benchmarking, it is recommended to use the benchmarking utilities provided by the testing package.



            A lot of this code is boilerplate benchmarking code. With the testing package you can be more confident in the accuracy of your benchmarks, especially since you're benchmarking goroutines.



            (I will leave switching to the testing package for you.)



            Performance bias



            sites[site]+pages[page]


            Adding strings through the + operator is slow. This could be biasing your results (ie if you have lots of very long strings), but that also depends on how many sites you test with.



            Without knowledge of your full usage, it's hard to tell.



            Accuracy



            time.Since(begin).Nanoseconds() / 1000000 // convert to milliseconds


            I would instead use .Seconds(). Any variation on the scale of milliseconds would be meaningless. From testing with one site and two pages, I received response times of 10288 (10s) and 8128 ms (8s) and an end time of 30073 ms (30s).



            Rather than converting to int64 I would keep the type as float64.



            String formatting



            fmt.Println("End.")
            fmt.Println(fmt.Sprintf("%d ms", time.Since(begin).Nanoseconds()/1000000))


            Should then be converted to:



            fmt.Printf("End.nTotal time: %.0fsn", time.Since(begin).Seconds())


            And, given the switch to float64



            fmt.Printf("Url : %vnResponse Time : %d msnn", benchmark.url, benchmark.time)


            Should instead be:



            fmt.Printf("Url: %snResponse Time: %.0fsnn", benchmark.url,
            benchmark.time)


            (Notice I use %s rather than %v.)



            Variable naming



            Variables can have shorter names, especially in shorter functions where their purpose is clear.




            • totalExecTimeChan becomes timeChan


            • totalExecTime becoems time


            • BenchmarkTry becomes tries

            I would argue that the names tc and t would be equally fine for the first two.



            Capitalization matters in Go. The variable BenchmarkTry and the type PageBenchmark would be exported. In this case it does not make a difference, but for larger programs and packages it would be important.



            Miscellaneous




            1. This cast is not needed.



              totalExecTime := int64(0)


              With the switch to float64, it can instead be:



              totalExecTime := 0.0


            2. Some of your comments extend beyond the 80-character column. It is useful to stay within 80 characters when viewing things split across your screen. Instead, move comments to the line before the code. (Some of these comments are superfluous, but you're learning so that's okay.)


            3. Store len(sites)*len(pages) in a constant, rather than recomputing it each time.


            Conclusion



            Here is the code I ended up with:



            package main

            import (
            "fmt"
            "net/http"
            "time"
            )

            const tries = 1000

            type pageBenchmark struct
            url string
            time float64


            func execBenchmark(url string, benchmarks chan pageBenchmark)
            // prevent blocked goroutine
            timeChan := make(chan float64, tries)
            time := 0.0

            // start all requests
            for i := 0; i < tries; i++
            go execHTTPRequest(url, timeChan)


            // catch new values from execHTTPRequest()
            for i := 0; i < tries; i++
            // wait to get value from goroutine
            time += <-timeChan


            benchmarks <- pageBenchmarkurl, time / tries


            // exec http request and attach exec time to channel
            func execHTTPRequest(url string, timeChan chan float64)
            begin := time.Now()
            _, _ = http.Get(url)
            timeChan <- time.Since(begin).Seconds()


            func main()
            sites := [...]string
            // sites


            pages := [...]string
            // pages


            const length = len(sites) * len(pages)

            // set size to prevent blocked goroutine
            benchmarks := make(chan pageBenchmark, length)

            begin := time.Now()

            fmt.Println("Beginning!n")

            // start all the goroutines
            for site := range sites
            for page := range pages
            go execBenchmark(sites[site]+pages[page], benchmarks)



            // catch and print benchmarks
            for i := 0; i < length; i++
            b := <-benchmarks
            fmt.Printf("Url: %snResponse Time: %.0fsnn", b.url, b.time)


            // print total execution time
            fmt.Printf("End.nTotal time: %.0fsn", time.Since(begin).Seconds())



            Hope this helps!





            share









            $endgroup$

















              0












              $begingroup$

              When running your program with the Go race detector, it found no race conditions. That's good!



              Benchmark through testing




              Is there a better/more effective way to achieve this task?




              For benchmarking, it is recommended to use the benchmarking utilities provided by the testing package.



              A lot of this code is boilerplate benchmarking code. With the testing package you can be more confident in the accuracy of your benchmarks, especially since you're benchmarking goroutines.



              (I will leave switching to the testing package for you.)



              Performance bias



              sites[site]+pages[page]


              Adding strings through the + operator is slow. This could be biasing your results (ie if you have lots of very long strings), but that also depends on how many sites you test with.



              Without knowledge of your full usage, it's hard to tell.



              Accuracy



              time.Since(begin).Nanoseconds() / 1000000 // convert to milliseconds


              I would instead use .Seconds(). Any variation on the scale of milliseconds would be meaningless. From testing with one site and two pages, I received response times of 10288 (10s) and 8128 ms (8s) and an end time of 30073 ms (30s).



              Rather than converting to int64 I would keep the type as float64.



              String formatting



              fmt.Println("End.")
              fmt.Println(fmt.Sprintf("%d ms", time.Since(begin).Nanoseconds()/1000000))


              Should then be converted to:



              fmt.Printf("End.nTotal time: %.0fsn", time.Since(begin).Seconds())


              And, given the switch to float64



              fmt.Printf("Url : %vnResponse Time : %d msnn", benchmark.url, benchmark.time)


              Should instead be:



              fmt.Printf("Url: %snResponse Time: %.0fsnn", benchmark.url,
              benchmark.time)


              (Notice I use %s rather than %v.)



              Variable naming



              Variables can have shorter names, especially in shorter functions where their purpose is clear.




              • totalExecTimeChan becomes timeChan


              • totalExecTime becoems time


              • BenchmarkTry becomes tries

              I would argue that the names tc and t would be equally fine for the first two.



              Capitalization matters in Go. The variable BenchmarkTry and the type PageBenchmark would be exported. In this case it does not make a difference, but for larger programs and packages it would be important.



              Miscellaneous




              1. This cast is not needed.



                totalExecTime := int64(0)


                With the switch to float64, it can instead be:



                totalExecTime := 0.0


              2. Some of your comments extend beyond the 80-character column. It is useful to stay within 80 characters when viewing things split across your screen. Instead, move comments to the line before the code. (Some of these comments are superfluous, but you're learning so that's okay.)


              3. Store len(sites)*len(pages) in a constant, rather than recomputing it each time.


              Conclusion



              Here is the code I ended up with:



              package main

              import (
              "fmt"
              "net/http"
              "time"
              )

              const tries = 1000

              type pageBenchmark struct
              url string
              time float64


              func execBenchmark(url string, benchmarks chan pageBenchmark)
              // prevent blocked goroutine
              timeChan := make(chan float64, tries)
              time := 0.0

              // start all requests
              for i := 0; i < tries; i++
              go execHTTPRequest(url, timeChan)


              // catch new values from execHTTPRequest()
              for i := 0; i < tries; i++
              // wait to get value from goroutine
              time += <-timeChan


              benchmarks <- pageBenchmarkurl, time / tries


              // exec http request and attach exec time to channel
              func execHTTPRequest(url string, timeChan chan float64)
              begin := time.Now()
              _, _ = http.Get(url)
              timeChan <- time.Since(begin).Seconds()


              func main()
              sites := [...]string
              // sites


              pages := [...]string
              // pages


              const length = len(sites) * len(pages)

              // set size to prevent blocked goroutine
              benchmarks := make(chan pageBenchmark, length)

              begin := time.Now()

              fmt.Println("Beginning!n")

              // start all the goroutines
              for site := range sites
              for page := range pages
              go execBenchmark(sites[site]+pages[page], benchmarks)



              // catch and print benchmarks
              for i := 0; i < length; i++
              b := <-benchmarks
              fmt.Printf("Url: %snResponse Time: %.0fsnn", b.url, b.time)


              // print total execution time
              fmt.Printf("End.nTotal time: %.0fsn", time.Since(begin).Seconds())



              Hope this helps!





              share









              $endgroup$















                0












                0








                0





                $begingroup$

                When running your program with the Go race detector, it found no race conditions. That's good!



                Benchmark through testing




                Is there a better/more effective way to achieve this task?




                For benchmarking, it is recommended to use the benchmarking utilities provided by the testing package.



                A lot of this code is boilerplate benchmarking code. With the testing package you can be more confident in the accuracy of your benchmarks, especially since you're benchmarking goroutines.



                (I will leave switching to the testing package for you.)



                Performance bias



                sites[site]+pages[page]


                Adding strings through the + operator is slow. This could be biasing your results (ie if you have lots of very long strings), but that also depends on how many sites you test with.



                Without knowledge of your full usage, it's hard to tell.



                Accuracy



                time.Since(begin).Nanoseconds() / 1000000 // convert to milliseconds


                I would instead use .Seconds(). Any variation on the scale of milliseconds would be meaningless. From testing with one site and two pages, I received response times of 10288 (10s) and 8128 ms (8s) and an end time of 30073 ms (30s).



                Rather than converting to int64 I would keep the type as float64.



                String formatting



                fmt.Println("End.")
                fmt.Println(fmt.Sprintf("%d ms", time.Since(begin).Nanoseconds()/1000000))


                Should then be converted to:



                fmt.Printf("End.nTotal time: %.0fsn", time.Since(begin).Seconds())


                And, given the switch to float64



                fmt.Printf("Url : %vnResponse Time : %d msnn", benchmark.url, benchmark.time)


                Should instead be:



                fmt.Printf("Url: %snResponse Time: %.0fsnn", benchmark.url,
                benchmark.time)


                (Notice I use %s rather than %v.)



                Variable naming



                Variables can have shorter names, especially in shorter functions where their purpose is clear.




                • totalExecTimeChan becomes timeChan


                • totalExecTime becoems time


                • BenchmarkTry becomes tries

                I would argue that the names tc and t would be equally fine for the first two.



                Capitalization matters in Go. The variable BenchmarkTry and the type PageBenchmark would be exported. In this case it does not make a difference, but for larger programs and packages it would be important.



                Miscellaneous




                1. This cast is not needed.



                  totalExecTime := int64(0)


                  With the switch to float64, it can instead be:



                  totalExecTime := 0.0


                2. Some of your comments extend beyond the 80-character column. It is useful to stay within 80 characters when viewing things split across your screen. Instead, move comments to the line before the code. (Some of these comments are superfluous, but you're learning so that's okay.)


                3. Store len(sites)*len(pages) in a constant, rather than recomputing it each time.


                Conclusion



                Here is the code I ended up with:



                package main

                import (
                "fmt"
                "net/http"
                "time"
                )

                const tries = 1000

                type pageBenchmark struct
                url string
                time float64


                func execBenchmark(url string, benchmarks chan pageBenchmark)
                // prevent blocked goroutine
                timeChan := make(chan float64, tries)
                time := 0.0

                // start all requests
                for i := 0; i < tries; i++
                go execHTTPRequest(url, timeChan)


                // catch new values from execHTTPRequest()
                for i := 0; i < tries; i++
                // wait to get value from goroutine
                time += <-timeChan


                benchmarks <- pageBenchmarkurl, time / tries


                // exec http request and attach exec time to channel
                func execHTTPRequest(url string, timeChan chan float64)
                begin := time.Now()
                _, _ = http.Get(url)
                timeChan <- time.Since(begin).Seconds()


                func main()
                sites := [...]string
                // sites


                pages := [...]string
                // pages


                const length = len(sites) * len(pages)

                // set size to prevent blocked goroutine
                benchmarks := make(chan pageBenchmark, length)

                begin := time.Now()

                fmt.Println("Beginning!n")

                // start all the goroutines
                for site := range sites
                for page := range pages
                go execBenchmark(sites[site]+pages[page], benchmarks)



                // catch and print benchmarks
                for i := 0; i < length; i++
                b := <-benchmarks
                fmt.Printf("Url: %snResponse Time: %.0fsnn", b.url, b.time)


                // print total execution time
                fmt.Printf("End.nTotal time: %.0fsn", time.Since(begin).Seconds())



                Hope this helps!





                share









                $endgroup$



                When running your program with the Go race detector, it found no race conditions. That's good!



                Benchmark through testing




                Is there a better/more effective way to achieve this task?




                For benchmarking, it is recommended to use the benchmarking utilities provided by the testing package.



                A lot of this code is boilerplate benchmarking code. With the testing package you can be more confident in the accuracy of your benchmarks, especially since you're benchmarking goroutines.



                (I will leave switching to the testing package for you.)



                Performance bias



                sites[site]+pages[page]


                Adding strings through the + operator is slow. This could be biasing your results (ie if you have lots of very long strings), but that also depends on how many sites you test with.



                Without knowledge of your full usage, it's hard to tell.



                Accuracy



                time.Since(begin).Nanoseconds() / 1000000 // convert to milliseconds


                I would instead use .Seconds(). Any variation on the scale of milliseconds would be meaningless. From testing with one site and two pages, I received response times of 10288 (10s) and 8128 ms (8s) and an end time of 30073 ms (30s).



                Rather than converting to int64 I would keep the type as float64.



                String formatting



                fmt.Println("End.")
                fmt.Println(fmt.Sprintf("%d ms", time.Since(begin).Nanoseconds()/1000000))


                Should then be converted to:



                fmt.Printf("End.nTotal time: %.0fsn", time.Since(begin).Seconds())


                And, given the switch to float64



                fmt.Printf("Url : %vnResponse Time : %d msnn", benchmark.url, benchmark.time)


                Should instead be:



                fmt.Printf("Url: %snResponse Time: %.0fsnn", benchmark.url,
                benchmark.time)


                (Notice I use %s rather than %v.)



                Variable naming



                Variables can have shorter names, especially in shorter functions where their purpose is clear.




                • totalExecTimeChan becomes timeChan


                • totalExecTime becoems time


                • BenchmarkTry becomes tries

                I would argue that the names tc and t would be equally fine for the first two.



                Capitalization matters in Go. The variable BenchmarkTry and the type PageBenchmark would be exported. In this case it does not make a difference, but for larger programs and packages it would be important.



                Miscellaneous




                1. This cast is not needed.



                  totalExecTime := int64(0)


                  With the switch to float64, it can instead be:



                  totalExecTime := 0.0


                2. Some of your comments extend beyond the 80-character column. It is useful to stay within 80 characters when viewing things split across your screen. Instead, move comments to the line before the code. (Some of these comments are superfluous, but you're learning so that's okay.)


                3. Store len(sites)*len(pages) in a constant, rather than recomputing it each time.


                Conclusion



                Here is the code I ended up with:



                package main

                import (
                "fmt"
                "net/http"
                "time"
                )

                const tries = 1000

                type pageBenchmark struct
                url string
                time float64


                func execBenchmark(url string, benchmarks chan pageBenchmark)
                // prevent blocked goroutine
                timeChan := make(chan float64, tries)
                time := 0.0

                // start all requests
                for i := 0; i < tries; i++
                go execHTTPRequest(url, timeChan)


                // catch new values from execHTTPRequest()
                for i := 0; i < tries; i++
                // wait to get value from goroutine
                time += <-timeChan


                benchmarks <- pageBenchmarkurl, time / tries


                // exec http request and attach exec time to channel
                func execHTTPRequest(url string, timeChan chan float64)
                begin := time.Now()
                _, _ = http.Get(url)
                timeChan <- time.Since(begin).Seconds()


                func main()
                sites := [...]string
                // sites


                pages := [...]string
                // pages


                const length = len(sites) * len(pages)

                // set size to prevent blocked goroutine
                benchmarks := make(chan pageBenchmark, length)

                begin := time.Now()

                fmt.Println("Beginning!n")

                // start all the goroutines
                for site := range sites
                for page := range pages
                go execBenchmark(sites[site]+pages[page], benchmarks)



                // catch and print benchmarks
                for i := 0; i < length; i++
                b := <-benchmarks
                fmt.Printf("Url: %snResponse Time: %.0fsnn", b.url, b.time)


                // print total execution time
                fmt.Printf("End.nTotal time: %.0fsn", time.Since(begin).Seconds())



                Hope this helps!






                share











                share


                share










                answered 6 mins ago









                esoteesote

                2,78611038




                2,78611038




















                    hunomina is a new contributor. Be nice, and check out our Code of Conduct.









                    draft saved

                    draft discarded


















                    hunomina is a new contributor. Be nice, and check out our Code of Conduct.












                    hunomina is a new contributor. Be nice, and check out our Code of Conduct.











                    hunomina is a new contributor. Be nice, and check out our Code of Conduct.














                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    Use MathJax to format equations. MathJax reference.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f215883%2fgolang-http-requests%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    名間水力發電廠 目录 沿革 設施 鄰近設施 註釋 外部連結 导航菜单23°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.7113923°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.71139計畫概要原始内容臺灣第一座BOT 模式開發的水力發電廠-名間水力電廠名間水力發電廠 水利署首件BOT案原始内容《小檔案》名間電廠 首座BOT水力發電廠原始内容名間電廠BOT - 經濟部水利署中區水資源局

                    Prove that NP is closed under karp reduction?Space(n) not closed under Karp reductions - what about NTime(n)?Class P is closed under rotation?Prove or disprove that $NL$ is closed under polynomial many-one reductions$mathbfNC_2$ is closed under log-space reductionOn Karp reductionwhen can I know if a class (complexity) is closed under reduction (cook/karp)Check if class $PSPACE$ is closed under polyonomially space reductionIs NPSPACE also closed under polynomial-time reduction and under log-space reduction?Prove PSPACE is closed under complement?Prove PSPACE is closed under union?

                    Is my guitar’s action too high? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)Strings too stiff on a recently purchased acoustic guitar | Cort AD880CEIs the action of my guitar really high?Μy little finger is too weak to play guitarWith guitar, how long should I give my fingers to strengthen / callous?When playing a fret the guitar sounds mutedPlaying (Barre) chords up the guitar neckI think my guitar strings are wound too tight and I can't play barre chordsF barre chord on an SG guitarHow to find to the right strings of a barre chord by feel?High action on higher fret on my steel acoustic guitar