The guide to concurrent programming Using Golang

Doron Segal
3 min readApr 12, 2020
Go Concurrent — Only one task can run in a specific time

Before I’m going to dive deep into concurrent programming with Go, let’s cover some basics.

The basics

What is GO Concurrent?
Concurrent computing is a form of computing in which several computations are executed concurrently — during overlapping time periods — instead of sequentially, with one completing before the next starts.
This is a property of a system — whether a program, computer, or a network — where there is a separate execution point or “thread of control” for each process. A concurrent system is one where a computation can advance without waiting for all other computations to complete.[Wikipedia]

What are GO channels?
Channels are a typed conduit through which you can send and receive values with the channel operator, <-. A simple example can be found here.

The GO Sync package
It provides a basic synchronization primitives such as mutual exclusion locks.

What is the Go routine?
Goroutines are functions that run concurrently, to some of you with Node.js experience, this basically the default behavior of the Node V8 engine.

Let’s add a simple example of using goroutines.

// The following example can be found here: https://gist.github.com/doron2402/283a54e4be9a12342b40a0584a6b772fpackage main

import (
"fmt"
"time"
)
func say(str string) {
time.Sleep(1 * time.Millisecond)
for i := 0; i < 10; i++ {
fmt.Printf("%d) %v\n", i, str)
}
}
func main() { go say("Hello")
go say("World")
go say("Bye")
// sleep for 100ms so we can see our app output
time.Sleep(100 * time.Millisecond)
}

The main function call, the say function 3 times.
go say(“Hello”)
go say(“World”)
go say(“Bye”)

Later we’re going to call time.Sleep so our program will wait before shutting down, this will help us see the output, but what if our goroutines will take longer than 100ms to execute? sync package to the rescue!

Now, let’s move to a more complex example using goroutines, channels and sync.WaitGroup

// Go channel example
// Example can be found here: https://gist.github.com/doron2402/411f184f2755303ce8ccc10d762d7dd6
package mainimport (
"fmt"
"sync"
)
// send only function
// n this goroutines func the ch is a write only channel
func sendOnlyMessage(ch chan<- int, wg *sync.WaitGroup) {
ch <- 42
wg.Done()
}
// receive only channel
// in this goroutines func the ch is read only channel
func receiveOnlyMessage(ch <-chan int, wg *sync.WaitGroup) {
fmt.Println(<-ch)
wg.Done()
}
func main() { wg := &sync.WaitGroup{}
ch := make(chan int) // channel default to 0 messages
wg.Add(2) go sendOnlyMessage(ch, wg) go receiveOnlyMessage(ch, wg) wg.Wait()}

Let’s go over the code, so what is the sync.WaitGroup?
sync.WaitGroup — A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished. [golang]

What it means that we would like for all of our goroutines to finish before exiting from our app. We start by creating a wait group wg := &sync.WaitGroup. Then we set the number of goroutines we would like to wait for, in this case, 2 wg.Add(2) . Later, we will pass our sync.WaitGroup pointer to the receive and send function so we can tell the wait group that the goroutine completed.

The channel helps us to send and receive data between function, in this example I created a channel that passes an integer ch := make(chan int). Than I pass the channel to both goroutines sendOnlyMessage and receiveOnlyMessage . The sendOnlyMessage will pass the number 42 into the channel, ch <- 42 , Than the receiveOnlyMessage goroutines will listen to the channel, get the value and print it, fmt.Println(<-ch) .
In both goroutines we add to call wg.Done() so our app know that he can exit once all goroutines are completed.

One, important thing to see is the difference between ch <-chan int vs ch chan<- int the first one is receive only channel and the other is write/send only channel, Go made it easy for us to pass the same channel but the function signature is different. Another example can found here.

I hope you find it useful, and it helps you understand the Golang concurrent programming.
If you have any question or would like a more complex example feel free to comment below.

--

--

Doron Segal

Rational optimist, Dad, Tech founder, Environmentalist, CTO Founder @TryPerDiem.com