Welcome to Golang Programs, Get the best new programs in your inbox, daily.

Concurrency

Popular programming languages such as Java and Python implement concurrency by using threads. Go takes a different route. Go uses the concurrency model called Communicating Sequential Processes (CSP). Networking, client-server or distributed computing programs that execute different pieces of code simultaneously, possibly on different processors or computers. Concurrency is a built-in feature of Go, and the Go runtime has great control over the programs that run with its concurrency features. Many other programming languages have third-party libraries (or extensions), but inherent concurrency is something unique to modern languages, and it is a core feature of Go's design. The basic building blocks Go proposes for structuring concurrent programs are goroutines and channels.

What are goroutines ?

The parts(threads) of an application(process) that run concurrently are called goroutines in Go or you can say a concurrently executing function in Go is called a goroutine. Goroutines let you run functions independent of each other.
Consider a program that has two functions, one function writes some output and other one that writes some other output, and assume that neither function calls each other. In a sequential program may call one function and then call the other, but in a concurrent program with two or more goroutines, calls to both functions can be active at the same time.

When a function is created as a goroutine, it's treated as an independent unit of work that gets scheduled and then executed on an available logical processor. The Go runtime scheduler which manages all the goroutines that are created and need processor time. The scheduler sits on top of the operating system, binding operating system's threads to logical processors which, in turn, execute goroutines. There is no one-to-one correspondence between a goroutine and an operating system thread. The scheduler controls everything related to which goroutines are running on which logical processors at any given time.

To run a function as a goroutine, call that function prefixed with the go statement.

Here is the example code block:

printCountry() // A normal function call that executes printCountry synchronously and waits for completing it
go printCountry() // A goroutine that executes printCountry asynchronously and doesn't wait for completing it

The difference between a normal function call and a goroutine is that a goroutine is created with the go statement. An executable Go program does have at least one goroutine; the goroutine that calls the main function is known as the main goroutine.

package main
import (
    "fmt"
    "time"
    "sync"
)   
type testConcurrency struct {
    min int
    max int
    country string
}
func printCountry(test *testConcurrency, groupTest *sync.WaitGroup) {   
    for i :=test.max ; i>test.min; i-- { 
            time.Sleep(1*time.Millisecond)          
            fmt.Println(test.country)
    }
    fmt.Println()
    groupTest.Done()    
}
func  main() {
    groupTest := new(sync.WaitGroup)
    japan := new(testConcurrency)
    china := new(testConcurrency)
    india := new(testConcurrency)
    japan.country = "Japan"
    japan.min = 0
    japan.max = 5
    china.country = "China"
    china.min = 0
    china.max = 5
    india.country = "India"
    india.min = 0
    india.max = 5
    go printCountry(japan, groupTest)
    go printCountry(china, groupTest)
    go printCountry(india, groupTest)
    groupTest.Add(3)
    groupTest.Wait()
}

What is wait group ?

Go's standard library provides several useful tools for working with synchronization. One that frequently comes in handy is sync.WaitGroup, a tool for telling one goroutine to wait until other goroutines complete.

A wait group is a message-passing facility that signals a waiting goroutine when it's safe to proceed. To use it, you tell the wait group when you want it to wait for something, and then you signal it again when that thing is done. A wait group doesn't need to know more about the things it's waiting for other than
(1) the number of things it's waiting for
(2) when each thing is done. You increment the first with groupTest.
Add, and as your task completes, you signal this with groupTest.Done. The groupTest.Wait function blocks

This program also synchronizes the execution using sync.WaitGroup while executing the goroutines; here function main is waiting for completion of the execution of goroutines using sync.WaitGroup .

go printCountry(japan, groupTest)
go printCountry(china, groupTest)
go printCountry(india, groupTest)

The program uses the WaitGroup type of sync package, which is used to wait for the program to finish all goroutines launched from the main function. Otherwise the goroutines would be launched from main function and then terminate the program before completing the execution of goroutines. The Wait method of the WaitGroup type waits for the program to finish all goroutines. The WaitGroup type uses a counter that specifies the number of goroutines, and Wait blocks the execution of the program until the WaitGroup counter is zero.

groupTest.Add(3)

The Add method is used to add a counter to the WaitGroup so that a call to the Wait method blocks execution until the WaitGroup counter is zero. Here a counter of three is added into the WaitGroup, one for each goroutine.

groupTest.Wait()

When the Wait method is called inside the main function, it blocks execution until the WaitGroup counter reaches the value of zero and ensures that all goroutines are executed.

When you run the program, the output would vary each time because the execution is randomly delaying inside the functions.