Concurrency and Parallelism In Golang
Inbuild concurrency and parallelism is really cool feature developed by Go developers. Before digging into concurrency and parallelism we shall clear some concepts like process, threads, etc.
Process
In computing, a process is an instance of a computer program that is being executed. A process simply having the following resources
- Executable code
- Operating system descriptors
- Stack and heap memory
- Security attributes
- Context (Context is registers and physical memory addressing)
All records are kept stored in a block called Process Control Block(PCB). And many processes communicating with each other via an inter-process communication mechanism. A simple example is if you open python shell then it creates a process and now you able to visible python shell editor.
Thread
Thread is simply a piece of code that will execute on the process or else you can say it process within the process is called a thread. It is also referred to as a “lightweight process”. A thread having its own
- Thread ID
- Program counter
- Registers and stack
Threads communicate with each other using the Thread Control Block(TCB). An example of the thread is like you opened Python shell editor and now started to executing the python command like print(“Hello World”). So command execution is nothing but the execution of a thread.
You can refer to this as to know more about threads and processes.
Now we have an idea about process and thread. Now it’s time to make the difference within parallelism and concurrency.
Concurrency is dealing multiple things at a single time while parallelism is doing multiple things at single time.
Rob Pike
Go has rich support for concurrency using goroutines and channels.
Goroutines
Goroutines are the functions or methods that are run concurrently with other goroutines. For creating goroutine you have to put go keyword in front of function and rest is go runtime will handle for you. A single thread can handle multiple goroutines concurrently. So these goroutines are communicated by channels.
go function_name(parameters)
refer to the following code for simple goroutine.
package mainimport “fmt”// printNumber: simply prints numbers
func printNumber(n int) {
for i := 0; i < n; i++ {
fmt.Println(n, “:”, i)
}
}// main function
func main() {
go printNumber(10)
// Wait to finish goroutine
var input string
fmt.Scanln(&input)
}
Above program consist of two goroutines. One is main and the other is printNumber function. After goroutine control immediately transfers to the next line and not wait for the go function to be executed (so above code contains wait to be user inputs as it executes a goroutine a while). multiple goroutines are communicating through channels.
Concurrency
As earlier, Concurrency is dealing with multiple things. A simple example of concurrency is when you are writing sentences down in your notebook from the textbook so a single time you could do write or read the sentence which you have to write or read. So this is called concurrency as you can deal with multiple things at a single time. Here in the example, multiple things are like reading and writing. And resources are like eyes and hands and they are switching context.
So concurrency is achieved in go using a go keyword with function. A single thread can have tons of goroutines. And those goroutines switching contexts as goroutine might wait for user input etc. The following example will show you things.
package main
import (
"fmt"
"runtime"
)// showNo - Shows no from 0 to 99
func showNo() {
for i := 0; i < 100; i++ {
fmt.Println("value of i=", i)
}
}// showAlphabets - shows alphabets from a-z
func showAlphabets() {
for j := 'a'; j <= 'z'; j++ {
fmt.Println("value of j=", string(j))
}
}// main function
func main() {
/*
In newer versions of go by default value GOMAXPROCS is set to no of logical processor you have
*/ runtime.GOMAXPROCS(1) for i := 0; i < 100; i++ {
go showNo()
go showAlphabets()
}
a := 0
fmt.Scanf("%d", &a)
}
So the above code contains runtime.GOMAXPROCS(1). this shows that a single logical processor is available for execution. So above code executing things concurrently. Single OS thread would be allocated over single logical processes and all goroutines are executed concurrently. In the above example, 100 goroutines are executing.
So this was about to concurrency. But many of thinking what about parallelism? Is is possible to be achieved? Can we have to write more code to make our code parallel? So….. please hold on. Go provide no headaches you to write code for parallelism. It achieve using a single line of statement.
This single line statement is runtime.GOMAXPROCS(int). If you provide GOMAXPROCS value is more than 1 then your code is totally parallel. As many OS threads are created and that thread is scheduled to the different logical processors for execution.
package main
import (
"fmt"
"runtime"
)// showNo - Shows no from 0 to 99
func showNo() {
for i := 0; i < 100; i++ {
fmt.Println("value of i=", i)
}
}// showAlphabets - shows alphabets from a-z
func showAlphabets() {
for j := 'a'; j <= 'z'; j++ {
fmt.Println("value of j=", string(j))
}
}// main function
func main() {
/*
In newer versions of go by default value GOMAXPROCS is set to no of logical processor you have
*/runtime.GOMAXPROCS(4)for i := 0; i < 100; i++ {
go showNo()
go showAlphabets()
}
a := 0
fmt.Scanf("%d", &a)
}
In the above code, there is GOMAXPROCS set to 4 means 4 logical processors are executing 4 threads in parallel. And those 4 threads are executing multiple goroutines inside themselves. Pretty fast and advanced. :)
From Go version 1.5 default value is to be set to this function is your machine's logical cores. If you have 4 logical cores with your machine then by the default value of GOMAXPROCS is 4. You can see here.
You could try yourself by setting GOMAXPROCS value negative.
You can refer to my code from Github.
So, concurrency and parallelism are totally different from each other. As one is dealing and another is doing, and Go provides lesser headache to programmer do the things related to concurrency and parallelism.