On the Hangzhou-based Gopher Meetup, Huang Qingbing from netease shared a relatively relaxed topic – “Visual Learning Go Concurrent Programming”. The following is a transcript of his speech.

Go was born for concurrency. In short, I think concurrency can be viewed as a way to construct a program, as shown below.

Parallelism & concurrency

To understand the difference between parallelism and concurrency, check out Rob Pike’s post. In this video, he explained the process of Go concurrency with Gopher GIF.

His views are summarized as follows:

  1. Concurrency is powerful

  2. Concurrency helps parallelism and makes parallelism (extension, etc.) easy

  3. Concurrency is not parallelism; concurrency focuses on architecture and concurrency focuses on execution, which are different but related.

Because today’s focus is not on theory, but on visualization of concurrent processes. Therefore, combining these two visualizations can intuitively understand the difference between concurrency and parallelism, after all, a picture is worth a thousand words. (Please copy the link and open it in your browser)

  • Concurrent: http://talks.bingohuang.com/2017/go-concurrency-visualize/pingpong36.html

  • Parallel: http://talks.bingohuang.com/2017/go-concurrency-visualize/parallelism.html

In general, parallelism is the programming technique of performing (usually related) computing tasks simultaneously, with two or more events occurring at the same time; Concurrency, on the other hand, is a programming technique that combines independent execution processes, in which two or more events occur at the same time interval.

Why focus on concurrency?

Today is a multi-core era, the world of concurrency. Moore’s Law is failing, requiring more attention to concurrent programming ideas.

But concurrent programming is not easy, and Go has good support for concurrency.

Concurrency in Go

Goroutine – Execute concurrently

  • Similar to & in UNIX

  • Much like threads, but lighter

  • A goroutine is a function that runs independently

  • When a goroutine blocks, the thread is blocked, but other Goroutines are not affected

Create a Goroutine with the keyword go, as follows

Channel

  • Similar to pipes in UNIX

  • It allows messages to be passed between goroutines

Here is a simple example of a common timer that can be visualized later.

Select

  • Similar to the switch common in the language

  • But its judgment condition is based on communication, not on equal quantity matching of values

Go makes concurrent programming easy

But here’s the problem:

  • How do we explain concurrency in Go?

  • How do we think about concurrency in Go?

  • Finally, how can we better practice concurrent programming in Go?

Here’s a magic weapon: GoTrace, an open source tool from Divan that visualizes Go concurrency. It mainly consists of two programs:

  • Gotrace (go) : analyzes the go tool trace execution result

  • Gothree (JS) : 3D image generation based on ThreeJs and WebGL

Thanks to Divan for providing this tool and a lot of Go concurrent material.

Hearing is but believing, seeing is believing

1.Hello,World!

Whatever language you write, you start with Hello World, and the code is very simple – single channel, single Goroutine, write once, read once.

Effect below (copy the link to http://talks.bingohuang.com/2017/go-concurrency-visualize/helloworld.html in the browser to open the can also be accessed directly) :

The blue line here shows the Goroutine running over time. Thin blue lines connecting ‘main’ and ‘#20’ mark the start and stop of goroutine, revealing their father-son relationship. Finally, the red arrow shows us the ‘send/receive’ action. It’s actually two separate actions that I’m trying to animate as A single transaction: send from A to B. The “#20” in the Goroutine name is the actual Goroutine internal ID, retrieved from the runtime by some means.

2. The timer

Remember from the Channel example, a timer is also typical – create a Channel, start a Goroutine, write data to the Channel after a given interval, and then return the Channel to the function caller. The caller blocks for a fixed amount of time before reading the channel. Let’s run 24 of these timers and try to visualize them.

Look at the effect (copy the link to http://talks.bingohuang.com/2017/go-concurrency-visualize/timer.html) :

Very graphic, isn’t it?

3. The ping pong balls

Two players

Look at the effect (copy the link into a browser open http://talks.bingohuang.com/2017/go-concurrency-visualize/pingpong2.html

It is recommended to open the link above in the PC browser, and you can interact with WebGL animation and play with it. You can slow it down, speed it up, and look at it from different angles.

Three players

The above is the common process of two table tennis players playing against each other. What if there are three players? Now, let’s run three athletes. Just make a few changes to the code and add a player:

Results are as follows: (copy the link into a browser open http://talks.bingohuang.com/2017/go-concurrency-visualize/pingpong3.html

36 players

Let’s look at a more complicated example, 36 runners.

Effect (copy the link in the browser open http://talks.bingohuang.com/2017/go-concurrency-visualize/pingpong36.html

Here we see each athlete taking his or her turn, and you might think why is that? Why do goroutine receivers follow such a strict order?

The answer is because the Go runtime maintains a first-in, first-out (FIFO) queue for the recipients (goroutines ready to receive messages from a particular channel), and in our case, each player is ready at exactly the moment he hits the ball on the table.

4. The prime sieve

With the simple examples above, let’s look at a more complex concurrency algorithm: the prime-sifting algorithm, or Eratostny algorithm, is an ancient algorithm used to find primes less than or equal to a given integer n. The core idea of the algorithm: first use the smallest prime number 2 to sieve, the multiples of 2 out; The next unfiltered number is prime (3 here). Use this prime number 3 to sift out multiples of 3… This is repeated until the sieve is finished.

The concurrent variation of this algorithm is to filter numbers with Goroutines — a Goroutine finds a prime number, and channels is used to pass numbers from the generator to the filter. When a prime number is found, it is passed to main via channel and then printed.

Of course, this algorithm is not very efficient, especially if you want to find a large number of prime numbers and look for the lowest high O complexity, but it is very elegant.

You can have a look at the appearance of the visual (http://talks.bingohuang.com/2017/go-concurrency-visualize/primesieve.html)

You can experience the animation in interactive mode. It really helps us understand the algorithm better because it’s graphical. The generate function goroutine emits each integer starting at 2. And each new filter function goroutine will filter multiples of certain primes – 2,3,5,7… The first number of each filter is a prime, which is passed to main and printed. If you rotate the image from top to bottom, you’ll see that all the numbers sent from Goroutine to Main are prime numbers.

It’s a beautiful algorithm, especially in 3D.

5. Others -Goroutines leak

Although Goroutine is a very lightweight thread, it should not be wasted. What happens if N goroutines leak?

Effect of http://talks.bingohuang.com/2017/go-concurrency-visualize/leak.html

It looks pretty, but it’s a ticking time bomb, so be aware of Goroutine leaks when coding.

An introduction to the use of Gotrace

One final word about the use of GoTrace, which is itself open source.

Go get-V-u github.com/divan/gotrace

The default branch (master) is developed based on Go 1.6. I recommend switching to the Go18 branch with Go 1.8 support.

Specific usage is as follows:

Running the go code directly does not work well, so it is recommended to generate trace, which should be preceded and followed by:

With Docker, you can use the following script:

It opens this browser automatically, you can adjust the perspective, you can zoom, rotate, bold, change the image.

Usage scenarios

Finally, I want to talk about usage scenarios. First of all, WHEN I saw it, I thought it was very cool. It will arouse people’s interest in learning Go. At the same time, we can also learn the concurrent mode of Go through it and explore the concurrent process of Go.