

Real life concurrency in Go - mattetti
http://matt.aimonetti.net/posts/2012/11/27/real-life-concurrency-in-go/

======
jgrahamc
It's a bit odd to do the time.Sleep in this code because it means that select
is often not able to receive on the ch channel:

    
    
      select {
          case r := <-ch:
              fmt.Printf("%s was fetched\n", r.url)
              responses = append(responses, r)
              if len(responses) == len(urls) {
                  return responses
              }
          default:
              fmt.Printf(".")
              time.Sleep(5e7)
          }
    

It would be better to use time.Tick

    
    
      ticker := time.Tick(50 * time.Millisecond)
    
      select {
          case r := <-ch:
              fmt.Printf("%s was fetched\n", r.url)
              responses = append(responses, r)
              if len(responses) == len(urls) {
                  return responses
              }
          case <-ticker:
              fmt.Printf(".")
          }
    

Also, there's no need to use a buffered channel. Each goroutine that's
handling a URL get can just wait for the send on the channel before
terminating.

    
    
      ch := make(chan *HttpResponse, len(urls)) // buffered
    

can just be

    
    
      ch := make(chan *HttpResponse)
    

And another thing that could be done is to not have asyncHttpGets return a
slice of *HttpResponse but have it return a channel and then range over it.
Then asyncHttpGets could run in its own goroutine and just close the channel
when done.

~~~
mattetti
Thanks, I'll make the appropriate changes.

------
redbad
This is indeed what Go is great for. But your code example is a bit wonky :)
Specifically,

    
    
        for {
            select {
            case r := <-ch:
                // do something with r
            default:
                fmt.Printf(".")
                time.Sleep(5e7)
            }
        }
    

You're needlessly blocking 50ms on every iteration. (Side note: time.Sleep(50
* time.Millisecond) better captures your intent.) Better to reformulate that
as

    
    
        for {
            select {
            case r := <-ch:
                // do something with r
            case <-time.After(50*time.Millisecond):
                fmt.Printf(".")
            }
        }
    

Or, if you don't need the dots in the output,

    
    
        for i := 0; i < cap(ch); i++ {
            r := <-ch
            // do something with r
        }

~~~
mattetti
Post updated with some of your suggestions as well as some from @jgrahamc
Thanks!

------
redbad

        Go implements OOP slightly differently than other
        languages. Functions are defined on an interface, 
        not a class or subclass.
    

This is not quite correct. Functions are defined on concrete types. Interfaces
are named collections of functions, used to describe behavior.

