Table of contents
1.
Introduction
2.
What is Concurrency?
3.
Concurrency in Go
4.
Goroutines
4.1.
Syntax
4.2.
Example
5.
Channels
5.1.
Syntax
5.2.
Example
6.
Go Concurrency Problems
7.
Illustration of the Sleeping Barber Problem
8.
Illustration of Checkpoint Synchronization
9.
Illustration of the Dining Philosophers Problem
10.
Illustration of the Producer-Consumer Problem
11.
FAQs
12.
Key Takeaways
Last Updated: Mar 27, 2024

Go Concurrency Problems

Author Rhythm Jain
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Concurrent programming is a broad subject, but it is also one of the most intriguing features of the Go programming language.

What is Concurrency?

Concurrency in computer science refers to the capacity of several elements or units of a program, algorithm, or issue to be run out-of-order or concurrently without impacting the conclusion.

Concurrency in Go

Go promotes a novel approach to concurrency in which shared values are transferred around via channels rather than explicitly shared by distinct threads of operation. Go's threading architecture does not support coincidence. It instead makes use of goroutines and channels. At any one moment, only one goroutine has access to the value.

Two crucial concepts make Go’s concurrency model work:

  1. Goroutines
  2. Channels

Goroutines

A goroutine is a function that may run alongside other functions. A goroutine is a lightweight thread that the Go runtime manages. We use the keyword "go" followed by a function call to construct a goroutine.

Syntax

go foo(x, y, z)


foo(x,y,z) is a coroutine or function.

Example

package main

import (
	"fmt"
	"time"
)

func foo(s string) {
	for i := 0; i < 5; i++ {
		fmt.Println(s,":",i)
		time.Sleep(100 * time.Millisecond)
	}
}

func main() {
	go foo("Hello")
	foo("World")
}

 

Output

World : 0
Hello : 0
Hello: 1
World: 1
Hello: 2
World 2
World : 3
Hello : 3
Hello:4
World: 4

 

This program is made up of three goroutines. The first goroutine is implicit and serves as the main function. The second goroutine is generated when we call go foo("Hello"). The third is a regular function call, not a goroutine.

Channels

A channel is a data pipeline that allows data to be sent and received. Channels let one goroutine convey structured data to another using the channel operator "<-."

Syntax

First, we must create a channel using the make command.

ch := make(chan int)


Data Flow

ch <- v    // Send v to channel ch.
v := <-ch  // Receive from ch, and
           // assign value to v.

Example

package main

import "fmt"

func sum(a []int, c chan int) {
	sum := 0
	for v := range a {
		sum += a[v]
	}
	c <- sum // send sum to c
}

func main() {
	a := []int{7, 2, 8, -9}

	c := make(chan int)
	go sum(a[:len(a)/2], c)
	go sum(a[len(a)/2:], c)
	x, y := <-c, <-c // receive from c
	fmt.Println(x, y)
}

Output

-1 9 


We used channel c to receive output from a goroutine “sum.”

Go Concurrency Problems

Now we will discuss some problems based on Go Concurrency.

Illustration of the Sleeping Barber Problem

The comparison is based on a fictitious barbershop with only one barber. There is a barbershop with one barber, one barber chair, and n chairs for clients to sit on if there are any. When there are no customers, the barber sleeps in his chair. When a customer arrives, he must rouse the barber. If there are a lot of clients and the barber is cutting someone's hair, the other customers either wait if there are empty chairs in the waiting area or leave if there are no empty chairs.

Source: Dribbble.com

Illustration of Checkpoint Synchronization

The problem of checkpoint synchronization is one of synchronizing several tasks. Consider a workplace where numerous employees are putting together the intricacies of a mechanism. When they have finished their labor, they will put the details together. Because there is no shop, workers who complete their task first must wait for others before beginning another. Putting pieces together is when jobs synchronize before diverging on their respective routes.

Illustration of the Dining Philosophers Problem

Five quiet philosophers occupy a circular table with plates of dinner. Each pair of neighboring philosophers is given a fork. Each philosopher must alternate between thinking and eating. On the other hand, a philosopher can only eat dinner if they have both left and right forks. Because one philosopher can only hold each fork, a philosopher can only utilize the fork if another philosophy does not. When a philosopher has finished eating, they must set down both forks so that the forks are available to others.

 

A philosopher can take either the fork on their right or the fork on their left when they become available, but they cannot begin eating until they have both forks. Eating is not restricted by the amount of dinner left or stomach space available; a limitless supply and infinite demand are assumed. The challenge is building a behavioral discipline (a concurrent algorithm) so that no philosopher will starve; that is, each can alternate between eating and thinking indefinitely, given that no philosopher can predict when others may desire to eat or ponder.

Source: Youtube

Illustration of the Producer-Consumer Problem

The Producer-Consumer problem is a classic multi-process synchronization problem, which means that we are attempting to create synchronization between several processes.

In the producer-consumer issue, there is one Producer who produces certain goods and one Consumer who consumes the Producer's products. Both producers and consumers share the same fixed-size memory buffer. The Producer's job is to make the item, store it in the memory buffer, and then start making more. The objective of the Consumer is to consume the item from the memory buffer.

Source: Educative.io

FAQs

  1. What are the advantages of Go Concurrency?
    It is cheap and lightweight. Therefore, It is less complicated as well as fast.
     
  2. What is a buffered channel?
    While creating a channel, we can provide a second argument that specifies the length buffer length while creating the channel. It is called a buffered channel. 
    Example ch := make(chan int, 100)
     
  3. What do you mean by concurrency?
    Concurrency is the ability of different parts or units of a program, algorithm, or problem to be executed out-of-order or simultaneously without affecting the outcome.

Key Takeaways

In this article, we have extensively discussed what Concurrrecy is, How do we acquire concurrency in Go Language. We learned about Goroutines and Channels, and then we came upon an illustration of some problems based on Go Concurrency. 

This blog is over, but the thirst for learning is not over yet. 

There is a whole library of such interesting blogs curated by experts.

We hope that this blog has helped you enhance your knowledge regarding Go Concurrency. If you would like to learn more, check out our articles on Process Synchronisation, which is significant in Operating Systems. Do upvote our blog to help other ninjas grow. Happy Coding!”

Live masterclass