Throttling Go routines


Yes, it’s complicated, But there are a couple of rules of thumb that should make things feel much more straightforward.

  • prefer using formal arguments for the channels you pass to go-routines instead of accessing channels in global scope. You can get more compiler checking this way, and better modularity too.
  • avoid both reading and writing on the same channel in a particular go-routine (including the ‘main’ one). Otherwise, deadlock is a much greater risk.

Here’s an alternative version of your program, applying these two guidelines. This case demonstrates many writers & one reader on a channel:

c := make(chan string)

for i := 1; i <= 5; i++ {
    go func(i int, co chan<- string) {
        for j := 1; j <= 5; j++ {
            co <- fmt.Sprintf("hi from %d.%d", i, j)
    }(i, c)

for i := 1; i <= 25; i++ {

It creates the five go-routines writing to a single channel, each one writing five times. The main go-routine reads all twenty five messages – you may notice that the order they appear in is often not sequential (i.e. the concurrency is evident).

This example demonstrates a feature of Go channels: it is possible to have multiple writers sharing one channel; Go will interleave the messages automatically.

The same applies for one writer and multiple readers on one channel, as seen in the second example here:

c := make(chan int)
var w sync.WaitGroup

for i := 1; i <= 5; i++ {
    go func(i int, ci <-chan int) {
        j := 1
        for v := range ci {
            fmt.Printf("%d.%d got %d\n", i, j, v)
            j += 1
    }(i, c)

for i := 1; i <= 25; i++ {
    c <- i

This second example includes a wait imposed on the main goroutine, which would otherwise exit promptly and cause the other five goroutines to be terminated early (thanks to olov for this correction).

In both examples, no buffering was needed. It is generally a good principle to view buffering as a performance enhancer only. If your program does not deadlock without buffers, it won’t deadlock with buffers either (but the converse is not always true). So, as another rule of thumb, start without buffering then add it later as needed.

Another explanation:

Go routines exec throttling:

Sends and Receives are blocking by default:

Golang – What is channel buffer size?


The buffer size is the number of elements that can be sent to the channel without the send blocking. By default, a channel has a buffer size of 0 (you get this with make(chan int)). This means that every single send will block until another goroutine receives from the channel. A channel of buffer size 1 can hold 1 element until sending blocks, so you’d get

c := make(chan int, 1)
c <- 1 // doesn't block
c <- 2 // blocks until another goroutine receives from the channel

Variable captured by func literal


it’s a common mistake for new comers in Go, and yes the var currentProcess changes for each loop, so your goroutines will use the last process in the slice l.processes, all you have to do is pass the variable as a parameter to the anonymous function, like this:

func (l *Loader) StartAsynchronous() []LoaderProcess {

    for ix := range l.processes {

        go func(currentProcess *LoaderProcess) {

            cmd := exec.Command(currentProcess.Command, currentProcess.Arguments...)
            log.LogMessage("Asynchronously executing LoaderProcess: %+v", currentProcess)

            output, err := cmd.CombinedOutput()
            if err != nil {
                log.LogMessage("LoaderProcess exited with error status: %+v\n %v", currentProcess, err.Error())
            } else {
                log.LogMessage("LoaderProcess exited successfully: %+v", currentProcess)

            time.Sleep(time.Second * TIME_BETWEEN_SUCCESSIVE_ITERATIONS)

        }(&l.processes[ix]) // passing the current process using index


    return l.processes

Another example :

Go features


  1. In Go a type definition is neither pointer nor value, it’s just a type.
  2. Go doesn’t have classes
  3. Go doesn’t have inheritance, it has interfaces for polymorphism and some sugar for automatic delegation (“struct embedding”).
  4. Simple build system. Want to compile for linux arm from your MacBook? GOOS=linux GOARCH=arm go build.
  5. Implicit interfaces.
  6. Great standard library. Go’s standard library covers JSON, Templating, HTTP (production grade), testing, benchmarking, etc, etc.
  7. Standard formatting.
  8. Documentation for free.

Deploying Go apps to Heroku

1. Make sure the app is running fine locally.

2. Install dep, with the project in $GOPATH/src/<user>/<project>, run dep init inside the project directory, dep ensure to generate the vendor files

3. Download and install Heroku CLI, run heroku login to login and heroku create to create the app, then heroku buildpacks:set heroku/go to set the build environment (ref:

4. Edit Gopkg.toml to include metadata.heroku section

go-version = "1.0"
build = [.]

5. Configure to load the git repo from and deploy to Heroku, all continuous build, test and integration.

Web Assembly and Go: A look to the future


When I look at modern web development I shudder; the ecosystem is so confusing for someone who has been out of touch as long as I have. Node, webpack, yarn, npm, frameworks, UMD, AMD, arghhh!

When Web Assembly(wasm) support landed in Go recently, I knew that the time was ripe for some experimentation.

I’ve decided that Web Assembly is the future of web development. It enables any language that can compile to wasm to be a “frontend” language.