Performance gains with goroutines
Waiting for Stragglers
Extending the length of the Sleep
command in the main program and hoping for good luck that all the underlings have finished their work in the meantime is obviously not a good solution. If the computer is busy with costly operations in other processes in the meantime, it is possible that the duration will extend to a few seconds, and the race is on again.
For every goroutine to have a guaranteed outcome, the main program and the routines have to communicate. At the end of the program flow, the main program has to wait until each routine has successfully completed before it can shut down the main process. In the form of the sync
package, Go offers some tools based on semaphores that do this job reliably.
The most elegant method, preferred by Go programmers, however, uses channels. These communication lines, reminiscent of Unix pipes, transport information from one part of the program to another. In addition, they block the program flow in a routine if nothing can be fed into the channel or read out from it temporarily and are thus ideal for synchronization, because individual program parts can wait for each other.
Channels, Synchronize!
Listing 4 fires off three different goroutines again, but doesn't output anything directly in them. Instead, the goroutines feed their output, which contains data of the string
type, into a channel named done
defined in line 5. The inverted arrow <-
pointing from the data to be written (e.g., "a"
) to the channel sends the data into the channel (Figure 3).
Listing 4
gochannel.go
01 package main 02 import "fmt" 03 04 func main() { 05 done := make(chan string) 06 07 go func() { done <- "a" }() 08 go func() { done <- "b" }() 09 go func() { done <- "c" }() 10 11 defer close(done) 12 13 for i := 0; i <= 2; i++ { 14 msg := <-done 15 fmt.Println(msg) 16 } 17 }
Depending on the free capacity in the channel, this is done either immediately, or the Go runtime blocks the execution of the respective goroutine until the channel can receive the data. It is very important that while one goroutine might block at any given time, other goroutines in the system continue to run unhindered and thus do not cause a hiccup in the program, but instead empower a high-performance system.
The output from Listing 4 is also non-deterministic, whether you will see abc or cba or bac is uncertain, because the single goroutines in this simple implementation don't coordinate their work with each other, and the main program only waits until all routines are finished – the order thus is rather random. What is guaranteed, though, is that the output will always contain three letters, which is an improvement over the previous race condition.
After firing off the goroutines, the main program uses the defer
statement in line 11 to stipulate that the done
channel will be closed after the program terminates; it then enters a for
loop, which uses the read operator <-
on the left (!) side of the channel variable to fetch the next value that exists in the channel in line 14 and assigns it to the msg
variable.
Synchronization with the previously spawned goroutines also occurs during this read operation. When the main program reaches the for
loop and the read operation for the first time, it is highly unlikely that any of the goroutines have had an opportunity to execute their write statements thus far. But this doesn't matter; if the channel is still empty, the program blocks in line 14 until data becomes available and the Go runtime lets one of the goroutines loose to perform its task. As soon as the first chunk of data has trickled in, the blocked read statement in the main program also notices that things are happening, obtains the available data, and the for
loop goes into the next round.
Precise Count
Now it becomes clear why, in this simple implementation, the for
loop in line 13 needs to know exactly how many data packages were fed into the channel by the goroutines in order to retrieve precisely that number. If the main program were simply to continue to ask the channel for data, the Go runtime would block the fourth read process for an infinite period of time, because no further data would be written to the channel from this point onward. A hanging main program would be the result.
« Previous 1 2 3 Next »
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
TUXEDO Computers Unveils Linux Laptop Featuring AMD Ryzen CPU
This latest release is the first laptop to include the new CPU from Ryzen and Linux preinstalled.
-
XZ Gets the All-Clear
The back door xz vulnerability has been officially reverted for Fedora 40 and versions 38 and 39 were never affected.
-
Canonical Collaborates with Qualcomm on New Venture
This new joint effort is geared toward bringing Ubuntu and Ubuntu Core to Qualcomm-powered devices.
-
Kodi 21.0 Open-Source Entertainment Hub Released
After a year of development, the award-winning Kodi cross-platform, media center software is now available with many new additions and improvements.
-
Linux Usage Increases in Two Key Areas
If market share is your thing, you'll be happy to know that Linux is on the rise in two areas that, if they keep climbing, could have serious meaning for Linux's future.
-
Vulnerability Discovered in xz Libraries
An urgent alert for Fedora 40 has been posted and users should pay attention.
-
Canonical Bumps LTS Support to 12 years
If you're worried that your Ubuntu LTS release won't be supported long enough to last, Canonical has a surprise for you in the form of 12 years of security coverage.
-
Fedora 40 Beta Released Soon
With the official release of Fedora 40 coming in April, it's almost time to download the beta and see what's new.
-
New Pentesting Distribution to Compete with Kali Linux
SnoopGod is now available for your testing needs
-
Juno Computers Launches Another Linux Laptop
If you're looking for a powerhouse laptop that runs Ubuntu, the Juno Computers Neptune 17 v6 should be on your radar.