Fwd: Golang Overview

44 views
Skip to first unread message

Skip Cave

unread,
Apr 28, 2024, 6:12:44 PMApr 28
to fo...@jsoftware.com

Interesting overview of Golang:

Learn the Powerful Tool of Go language Concurrency Programming through three examples — Goroutine

Jerry Wang

6 min readMar 18, 2024

Go language (also known as Golang) is a programming language developed by Google, renowned in the programming field for its simplicity, efficiency, and built-in support for concurrent programming.

In Go language, goroutine is a powerful feature for the creation and management of lightweight threads.

This article will introduce the concept of goroutine, its applications, and provide specific examples to demonstrate its usage to those who are unfamiliar with Go language.

1. Concept of Goroutine

Goroutine is a lightweight thread used for concurrent execution in Go language. Compared to traditional threads, goroutines are much cheaper to create and destroy, allowing the easy creation of numerous goroutines within the same program without degrading performance. Goroutines communicate with each other through channels, making concurrent programming straightforward and safe.

2. Applications of Goroutine

As the saying goes, “Give roses to the beloved and swords to the warriors.” Given the remarkable capabilities of Goroutine, the field of concurrent programming is its stage to shine.

Goroutine makes its presence felt in the following application scenarios:

  • Concurrent task execution: Goroutines can be used to execute multiple tasks at the same time, improving program performance.
  • Non-blocking I/O operations: Goroutines ensure that other tasks continue to execute during I/O operations, rather than waiting synchronously for I/O to complete.
  • Event-driven programming: Goroutines are suitable for event handling, such as listening to HTTP requests, processing user input, etc.
  • Concurrent algorithms: Implementing algorithms that require parallel computation is easier with goroutines, facilitating the management of concurrently executing parts.
  • Scheduled tasks: Goroutines, combined with timers, can implement tasks that execute on a schedule.

3. Specific Examples of Goroutine

Let’s explain through some specific examples.

Example 1: Simple Concurrent Task Execution

As a warm-up, let’s start with some simple “Hello World” level examples to get familiar with the usage of Goroutine.

Source code is as follows:

import (
"fmt"
"sync"
)
func printNumbers(wg *sync.WaitGroup) {
defer wg.Done()
for i := 1; i <= 5; i++ {
fmt.Printf("%d ", i)
}
}
func printLetters(wg *sync.WaitGroup) {
defer wg.Done()
for char := 'a'; char <= 'e'; char++ {
fmt.Printf("%c ", char)
}
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
go printNumbers(&wg)
go printLetters(&wg)
wg.Wait()
}

Save the above source code in a .go file, such as 1.go, and then execute the command line go run 1.go to see the following output:

In this example, we created two goroutines using the go keyword, one for printing numbers and the other for printing letters. The call to the sync.WaitGroup function waits for these two goroutines to complete. This is one of the most commonly used synchronization mechanisms in Go's concurrent programming.

Example 2: Concurrently Downloading Multiple Web Pages

Source code is as follows:

import (
"fmt"
"io/ioutil"
"net/http"
"sync"
)
func fetch(url string, wg *sync.WaitGroup) {
defer wg.Done()
response, err := http.Get(url)
if err != nil {
fmt.Printf("Error fetching %s: %v\n", url, err)
return
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Printf("Error reading response body from %s: %v\n", url, err)
return
}
fmt.Printf("Length of %s: %d\n", url, len(body))
}
func main() {
var wg sync.WaitGroup
urls := []string{"https://www.baidu.com", "https://cloud.tencent.com/", "https://www.qq.com/"}
for _, url := range urls {
wg.Add(1)
go fetch(url, &wg)
}
wg.Wait()
}

After executing the above source code, the console prints the length of the homepage HTML files for three websites (Baidu, QQ, and Tencent Cloud Community).

This example demonstrates how to use goroutines to concurrently download multiple web pages. Each webpage is downloaded in a separate goroutine, reducing the time required to complete the download tasks.

From the source code, it can be seen that if we were to implement this requirement using a traditional programming language like Java, we would need to use Java’s Thread class and some cumbersome synchronization mechanism codes. However, using Go language, the task of starting goroutines and reading HTML page data based on URLs can be easily accomplished with the concise line go fetch(url, &wg), greatly simplifying the code.

Example 3: Implementing the Producer-Consumer Model Through Channels

The producer-consumer model is one of the essential concepts in operating system courses. We use the func keyword to define two functions, one for the producer and one for the consumer. The producer function uses the time.Sleep method to produce a sequence of positive integers 1,2,3,4,5 every 0.5 seconds. Correspondingly, the consumer function consumes a positive integer every 0.5 seconds.

import (
"fmt"
"sync"
"time"
)
func producer(ch chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 1; i <= 5; i++ {
ch <- i
fmt.Printf("Produced: %d\n", i)
time.Sleep(time.Millisecond * 500) // Simulate a delay in the production process
}
close(ch)
}
func consumer(ch <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for num := range ch {
fmt.Printf("Consumed: %d\n", num)
time.Sleep(time.Millisecond * 200) // Simulate a delay in the consumption process
}
}
func main() {
var wg sync.WaitGroup
ch := make(chan int, 3) // Create a buffered channel with a capacity of 3
wg.Add(2)
go producer(ch, &wg)
go consumer(ch, &wg)
wg.Wait()
}

Executing the above Go source code outputs a sequence of produced integers followed by consumption, and so on.

This example demonstrates how to use goroutines and channels to implement the producer-consumer model. The producer sends data to the channel, and the consumer receives and processes data from the channel, achieving concurrent production and consumption through goroutines.

We used a buffered channel with a capacity of 3. Buffered channels allow writing to the channel even when it is not fully read, which is very useful when the producer and consumer operate at different speeds.

In the producer function producerch is a write-only integer channel, and wg is a pointer of type sync.WaitGroup, used to wait for all goroutines to complete. In this function, the producer sends the integer i to the channel with ch <- i, indicating a product has been produced. Then, it prints the information of the produced product with fmt.Printf and simulates the production process delay with time.Sleep. Finally, it closes the channel with close(ch), indicating that the producer will no longer send data to the channel.

Looking at the consumer function consumer,

ch is a read-only integer channel, and wg is a pointer of type sync.WaitGroup. In this function, the consumer receives an integer from the channel with num := <-ch, indicating a product has been consumed. Then, it prints the information of the consumed product with fmt.Printf and simulates the consumption process delay with time.Sleep. This loop continues until the channel is closed, at which point range ch will exit.

Conclusion

Through the three examples introduced in this article, we can see the strength of goroutines. With the combination of goroutines and channels, as well as the use of sync.WaitGroup, Go language offers a powerful and concise mechanism for concurrent





Skip Cave
Cave Consulting LLC

Toby Thain

unread,
Apr 29, 2024, 12:22:11 PMApr 29
to 'Skip Cave' via forum
On 2024-04-28 6:12 p.m., 'Skip Cave' via forum wrote:
>
> Interesting overview of Golang:
>
>
> Learn the Powerful Tool of Go language Concurrency Programming through
> three examples — Goroutine
>



Super offtopic and possibly 'ai' generated?

No thanks.
--T

Skip Cave

unread,
Apr 29, 2024, 2:18:24 PMApr 29
to fo...@jsoftware.com
I thought it was interesting to see how Golang handled concurrency...

Skip

Skip Cave
Cave Consulting LLC

To unsubscribe from this group and stop receiving emails from it, send an email to forum+un...@jsoftware.com.

Scott Locklin

unread,
May 2, 2024, 11:07:17 AMMay 2
to fo...@jsoftware.com
Goroutines are one of the many nice features of golang, but the real magic is the scheduler. Allocating threads in userspace allows the scheduler to optimize in ways pthreads/the OS can't, especially with help from the VM, which it is tightly embedded into. They also have less memory and latency overhead if you spin up a bunch of them. Very useful for building big networky things as Google engineers do; aka servicing lots of network connections or devops stuff without necessarily doing a lot of work for each one. Not so useful for grinding through numbers as J does, though according to the Wiki, Dyalog has them somehow. This new TSDB thing (unhelpfully named 'the platform') also seems to have something like them. Not sure what they're used for; Q works fine using normal OS threads.


FWIIW I've seen lots of back end code where people try to build big networky service things in Golang, Rust, C++, even Haskell; the Golang stuff always ends up "just working," shipping on time and not breaking very often. It's a very small language conceptually: sort of like C, but it includes a lot of stuff for doing useful work, especially for network back ends. 

-SL
Reply all
Reply to author
Forward
0 new messages