Golang HTTP requestsHandling HTTP requestsGolang HTTP status checkerGolang concurrent HTTP requestUnit testing HTTP requestsProxying Socket.io requests and other HTTP requestsGolang Tour Web Crawler ExerciseGolang HTTP request retry codeCustomizing errors based on HTTP status code in golangHTTP Load test with GolangMaking multiple HTTP requests to Twitter

I'm just a whisper. Who am I?

How to make a list of partial sums using forEach

Limit max CPU usage SQL SERVER with WSRM

Air travel with refrigerated insulin

What is the smallest number n> 5 so that 5 ^ n ends with "3125"?

In One Punch Man, is King actually weak?

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

How to understand "he realized a split second too late was also a mistake"

If Captain Marvel (MCU) were to have a child with a human male, would the child be human or Kree?

Overlapping circles covering polygon

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

Personal or impersonal in a technical resume

Why would five hundred and five be same as one?

Can I cause damage to electrical appliances by unplugging them when they are turned on?

Giving feedback to someone without sounding prejudiced

Alignment of six matrices

Quoting Keynes in a lecture

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

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

ContourPlot — How do I color by contour curvature?

Isometric embedding of a genus g surface

Pre-Employment Background Check With Consent For Future Checks

What is this high flying aircraft over Pennsylvania?

What should be the ideal length of sentences in a blog post for ease of reading?



Golang HTTP requests


Handling HTTP requestsGolang HTTP status checkerGolang concurrent HTTP requestUnit testing HTTP requestsProxying Socket.io requests and other HTTP requestsGolang Tour Web Crawler ExerciseGolang HTTP request retry codeCustomizing errors based on HTTP status code in golangHTTP Load test with GolangMaking 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. mainroutine: start a benchmark (goroutine) foreach 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


Actually, this piece of code works but I'm not sure that it works as intended.



  • Is that the case?

  • 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. mainroutine: start a benchmark (goroutine) foreach 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


    Actually, this piece of code works but I'm not sure that it works as intended.



    • Is that the case?

    • 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. mainroutine: start a benchmark (goroutine) foreach 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


      Actually, this piece of code works but I'm not sure that it works as intended.



      • Is that the case?

      • 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. mainroutine: start a benchmark (goroutine) foreach 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


      Actually, this piece of code works but I'm not sure that it works as intended.



      • Is that the case?

      • 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 8 mins ago









      Jamal

      30.4k11121227




      30.4k11121227






      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 43 secs 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

                    Why is a white electrical wire connected to 2 black wires?How to wire a light fixture with 3 white wires in box?How should I wire a ceiling fan when there's only three wires in the box?Two white, two black, two ground, and red wire in ceiling box connected to switchWhy is there a white wire connected to multiple black wires in my light box?How to wire a light with two white wires and one black wireReplace light switch connected to a power outlet with dimmer - two black wires to one black and redHow to wire a light with multiple black/white/green wires from the ceiling?Ceiling box has 2 black and white wires but fan/ light only has 1 of eachWhy neutral wire connected to load wire?Switch with 2 black, 2 white, 2 ground and 1 red wire connected to ceiling light and a receptacle?

                    कुँवर स्रोत दिक्चालन सूची"कुँवर""राणा कुँवरके वंशावली"

                    सि.चक भराडी, कोश्याँकुटोली तहसील इन्हें भी देखें बाहरी कड़ियाँ दिक्चालन सूची(निर्देशांक ढूँढें)www.uttara.gov.inउत्तराखण्ड - भारत सरकार के आधिकारिक पोर्टल परउत्तराखण्ड सरकार का आधिकारिक जालपृष्ठउत्तराखण्डउत्तरा कृषि प्रभासंबढ़ाने मेंसं