Go Basic: Understanding Goroutines, Channels, Select, Timeouts in Go

Let’s dive into the exciting world of Goroutines, Channels, Select, Timeoutsin Go. Exploring concurrency, including goroutines and channels.😄

full lessons here👇:
https://programmerscareer.com/golang-basic-skill/

Generated by AI, there may be errors, for reference only

Topic: Introduction to Concurrency

Concurrency is a core concept in Go, and it refers to making progress on more than one task simultaneously. In computer programming, a concurrent program is one where multiple tasks are in progress at the same time, but not necessarily executing simultaneously.

In Go, concurrency is achieved using goroutines, which are super lightweight processes (or threads). They are cheaper than threads, and their management is abstracted away from the developer. Go runtime contains a scheduler that coordinates the execution of a large number of goroutines and this is done on a small number of threads.

Topic: Goroutines

A goroutine is a lightweight thread managed by the Go runtime. You can create a goroutine simply by adding the keyword go in front of a function call, like this:

1
go funcName()

This starts the execution of funcName concurrently and Go schedules it to run on a logical processor.

Let’s take a simple example:

1
2
3
4
5
6
7
8
9
10
func hello() {  
fmt.Println("Hello World!")
}

func main() {
go hello()
fmt.Println("I'm listening…")
// wait for a while so that the program doesn’t exit immediately
time.Sleep(1 * time.Second)
}

We use the Sleep function from the time package to pause the main goroutine’s execution for 1 second. This gives the hello goroutine enough time to finish, so we’re able to see its output.

That’s just a beginner’s peek into goroutines. They’re a rich and powerful aspect of Go, which allow us to write elegant and efficient concurrent code.

Topic: Channels

In Go, Channels are pipes through which goroutines can communicate. The syntax to create a new channel is make(chan val-type), where val-typeindicates the type of data we can send through the channel.

Here’s a simple example of sending and receiving messages through a channel:

1
2
3
4
5
6
7
8
9
10
11
func main() {  
messages := make(chan string)

go func() {
messages <- "Hello, Gopher"
}()

message := <- messages
fmt.Println(message)

}

In this example, we first make a channel of strings. Then we spawn a goroutine which sends a “Hello, Gopher” message on the channel. In the main goroutine, we receive the message from the channel and print it out.

Notice how the data flows in the direction of the arrow.

Topic: Buffered Channels

By default, channels are unbuffered, meaning they will only accept sends if there is a corresponding receive ready to take the sent value. Buffered channels accept a limited number of values without a corresponding receiver.

Here’s an example:

1
2
3
4
5
6
7
8
9
func main() {  
buffChannel := make(chan string, 2)
buffChannel <- "buffered"
buffChannel <- "channel"

fmt.Println(<-buffChannel)
fmt.Println(<-buffChannel)

}

Here we create a buffered channel of size 2. Since the channel is buffered, we can send values into the channel without corresponding concurrent receive calls.

Topic: Select in Go

The select statement in Go allows us to work with multiple channels simultaneously. A select blocks until one of its cases can run, then it executes that case. If multiple cases are ready, it chooses one at random.

Let’s see how it works in an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func fibonacci(c, quit chan int) {  
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}

func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}

We create two channels c and quit. Then we launch a goroutine that sends some integers to channel c and then sends 0 to quit channel. The fibonacci function plays with select, where in each iteration it tries to casefrom channel c or quit.

Topic: Default Selection and Timeouts

If none of the cases in select are ready, then the default case will be executed. This is how you can implement non-blocking select statements.

When combined with time.Afterselect becomes a great way to implement timeouts. time.After returns a channel that will send the current time after the specified duration.

Here’s how you can do it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func main() {  
c := make(chan string, 1)

go func() {
time.Sleep(2 * time.Second)
c <- "result"
}()

select {
case res := <-c:
fmt.Println(res)
case <-time.After(1 * time.Second):
fmt.Println("timeout")
}

}

In this program, the select is waiting to receive a message from the cchannel. However, it will only wait for 1 second because of time.After(1 * time.Second). After 1 second, time.After sends the current time, causing the select to unblock and print “timeout”.

Topic: Real World Uses of Concurrency

Now, you might be wondering, “Where is concurrency used in the real world?”. Concurrency enables programs to perform several tasks at once, which can lead to better use of system resources and improved performance.

  1. Server Applications: Web and application servers use concurrency to manage multiple connections from clients at the same time. For example, when a user makes a request to a website, the server handling that website’s traffic uses a separate goroutine to handle each individual request. This allows the server to handle multiple requests simultaneously, without making other users wait while one user’s request is being sent or processed.
  2. Data Analysis and Big Data: Data analysis often involves the processing of large amounts of data, which can take a long time if done sequentially. Solutions can leverage the power of concurrency to analyze different subsets of data concurrently, reducing overall processing time.
  3. Game Development: In video games, concurrency can be used to handle user input, render graphics, run AI logic, and more, all at the same time. This way a game can maintain smooth visuals and responsive controls even under heavy load.
  4. Distributed Systems: In distributed and cloud-based systems, it’s often necessary to communicate with multiple servers at once. Concurrency can perform these communications simultaneously to increase system oversight and cohesion.
  5. Multithreading Operations: Similar to server applications, GUI based applications also use concurrency to ensure that the User Interface thread never blocks and provides a seamless user experience.

As we can see, the applications of concurrency are wide and varied. Once you master it, you’ll be able to write more efficient and effective Go programs.

中文文章: https://programmerscareer.com/zh-cn/go-basic-09/
Author: Wesley Wei – Twitter Wesley Wei – Medium
Note: If you choose to repost or use this article, please cite the original source.

Go Basic: Understanding File Paths, Directories, Temporary Files and Directories, Embed Directive in Go Go Basic: Understanding Reading Files, Writing Files, Line Filters in Go

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×