Each thing I learn in Go, I find myself trying to refer to it as I would in another language (thinking of structs as Classes, for example.)

There are however some differences with the Go implementation of these concepts.  In this post I wanted to take some material I’ve been reading about and learning about in various courses and books.  Specifically, I’d like to refer to the concept of concurrency.


A goroutine is a way of running functions concurrently.  In Grails there is a concept of using “promises” and tasks… and this is kinda similar.  But keep in mind that concurrent doesn’t necessarily mean parallel.

In my Port Scanner, I was originally running each check on a port in a range sequentially.  It would take several min to iterate over a list of 8000 ports.  However, when I applied the concept of GoRoutines, I got this down to 20 seconds to run over 8,000 localhost ports.

Setting Up GoRoutines

To make use of GoRoutines we need to define a wait group.  The concept of a WaitGroup works like this:

  1. we define a wait group
  2. we define how many groups (concurrent functions) we’ll be doing
  3. we call the function using the “go” keyword (defining it as a Go Routine)
  4. Once the function process is done, we mark the group as done.

In practicality it would look like this:

[pastacode lang=”c” manual=”var%20wg%20sync.WaitGroup%0Awg.Add(4)%09%09%2F%2F%203s%20to%20run%201000%20ports%20on%204%20concurrent%20groups%0A%09go%20check_port(host%2C%20start_port%2C%20end_port_set1)%0A%09go%20check_port(host%2C%20(end_port_set1%20%2B%201)%2C%20end_port_set2)%0A%09go%20check_port(host%2C%20(end_port_set2%20%2B%201)%2C%20end_port_set3)%0A%09go%20check_port(host%2C%20(end_port_set3%20%2B%201)%2C%20end_port)%0A%09wg.Wait()%0A%0Afunc%20check_port(host%20string%2C%20start_port%2C%20end_port%20int)%20%7B%0A%0A%09for%20i%20%3A%3D%20start_port%3B%20i%20%3C%3D%20end_port%3B%20i%2B%2B%20%7B%0A%09%09%2F%2Ffmt.Println(‘%5Cn’)%0A%09%09qualified_host%20%3A%3D%20fmt.Sprintf(%22%25s%25s%25d%22%2C%20host%2C%20%22%3A%22%2C%20i)%0A%09%09conn%2C%20err%20%3A%3D%20net.DialTimeout(%22tcp%22%2C%20qualified_host%2C%2010*time.Millisecond)%20%20%2F%2F%20Got%20the%20timeout%20code%20from%3A%20https%3A%2F%2Fstackoverflow.com%2Fquestions%2F37294052%2Fgolang-why-net-dialtimeout-get-timeout-half-of-the-time%0A%09%09if%20err%20!%3D%20nil%20%7B%0A%09%09%09continue%0A%09%09%7D%0A%09%09fmt.Fprintf(conn%2C%20%22GET%20%2F%20HTTP%2F1.0%5Cr%5Cn%5Cr%5Cn1%5Cn22%5Cn%5Cn%5Cn%5Cn%22)%0A%09%09conn.SetReadDeadline(time.Now().Add(10*time.Millisecond))%0A%0A%09%09%2F%2F%20swapping%20bufio%20reads%20to%20reading%20buffers%20as%20bytes%20gets%20huge%20performance%20increase%3A%208000%20ports%20in%2020s%20(vs%201min%2010s%20using%20bufio%20reads)%0A%09%09buff%20%3A%3D%20make(%5B%5Dbyte%2C%201024)%0A%09%09n%2C%20_%20%3A%3D%20conn.Read(buff)%0A%09%09fmt.Printf(%22Port%3A%20%25d%25s%5Cn%22%2Ci%2C%20buff%5B%3An%5D)%0A%09%7D%0A%09wg.Done()%0A%7D” message=”” highlight=”” provider=”manual”/]

The first line defines the variable wg to hold the value for the WaitGroup method of the sync package (which will need to be imported.)

wg then makes use of the built in method Add() and in this case I put in the value of 4 wg.Add(4) which will run 4 concurrent runs.

Each concurrent call is defined as:

go [function name](params)

In this case:

go check_port(host, start_port, end_port_set1)…

At the bottom of this list of calls there’s a wait invoked: wg.Wait()

Lastly, the function itself has a wg.Done() at the end of the logic.

Channels in Go

Channels are a complex subject for me.  At first, I thought it was the magic that made concurrency happen in Go. Instead, I discovered that GoRoutines are how concurrency is applied in a go app.  Channels offer the ability for GoRoutines to share data back and forth.

I initially thought of channels as a “Thread,” as in other languages.

However, in reading this programmer’s blog post, I discovered some differences to threads: http://tleyden.github.io/blog/2014/10/30/goroutines-vs-threads/

You can see their full bulleted list of differences there.  I’ll just mention a couple highlights:

  1. GoRoutines can be run at a factor more than Threads on a system.
  2. GoRoutines have a mechanism to share and talk between GoRoutines (channels.)

Channels are mechanisms to share data between GoRoutines.

More info on channels:


Comments are closed