github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2012/concurrency.slide (about)

     1  # This is a file.
     2  
     3  Go Concurrency Patterns
     4  
     5  Rob Pike
     6  Google
     7  http://golang.org/s/plusrob
     8  @rob_pike
     9  http://golang.org
    10  
    11  * Video
    12  
    13  This talk was presented at Google I/O in June 2012.
    14  
    15  .link http://www.youtube.com/watch?v=f6kdp27TYZs Watch the talk on YouTube
    16  
    17  * Introduction
    18  
    19  * Concurrency features in Go
    20  
    21  People seemed fascinated by the concurrency features of Go when the language was first announced.
    22  
    23  Questions:
    24  
    25  - Why is concurrency supported?
    26  - What is concurrency, anyway?
    27  - Where does the idea come from?
    28  - What is it good for?
    29  - How do I use it?
    30  
    31  * Why?
    32  
    33  Look around you. What do you see?
    34  
    35  Do you see a single-stepping world doing one thing at a time?
    36  
    37  Or do you see a complex world of interacting, independently behaving pieces?
    38  
    39  That's why. Sequential processing on its own does not model the world's behavior.
    40  
    41  * What is concurrency?
    42  
    43  Concurrency is the composition of independently executing computations.
    44  
    45  Concurrency is a way to structure software, particularly as a way to write clean code that interacts well with the real world.
    46  
    47  It is not parallelism.
    48  
    49  * Concurrency is not parallelism
    50  
    51  Concurrency is not parallelism, although it enables parallelism.
    52  
    53  If you have only one processor, your program can still be concurrent  but it cannot be parallel.
    54  
    55  On the other hand, a well-written concurrent program might run efficiently in parallel on a multiprocessor. That property could be important...
    56  
    57  For more on that distinction, see the link below. Too much to discuss here.
    58  
    59  .link http://golang.org/s/concurrency-is-not-parallelism
    60  
    61  * A model for software construction
    62  
    63  Easy to understand.
    64  
    65  Easy to use.
    66  
    67  Easy to reason about.
    68  
    69  You don't need to be an expert!
    70  
    71  (Much nicer than dealing with the minutiae of parallelism (threads, semaphores, locks, barriers, etc.))
    72  
    73  * History
    74  
    75  To many, the concurrency features of Go seemed new.
    76  
    77  But they are rooted in a long history, reaching back to Hoare's CSP in 1978 and even Dijkstra's guarded commands (1975).
    78  
    79  Languages with similar features:
    80  
    81  - Occam (May, 1983)
    82  - Erlang (Armstrong, 1986)
    83  - Newsqueak (Pike, 1988)
    84  - Concurrent ML (Reppy, 1993)
    85  - Alef (Winterbottom, 1995)
    86  - Limbo (Dorward, Pike, Winterbottom, 1996).
    87  
    88  * Distinction
    89  
    90  Go is the latest on the Newsqueak-Alef-Limbo branch, distinguished by first-class channels.
    91  
    92  Erlang is closer to the original CSP, where you communicate to a process by name rather than over a channel.
    93  
    94  The models are equivalent but express things differently.
    95  
    96  Rough analogy: writing to a file by name (process, Erlang) vs. writing to a file descriptor (channel, Go).
    97  
    98  * Basic Examples
    99  
   100  * A boring function
   101  
   102  We need an example to show the interesting properties of the concurrency primitives.
   103  
   104  To avoid distraction, we make it a boring example.
   105  
   106  .play concurrency/support/boring.go /START/,/STOP.*/
   107  
   108  * Slightly less boring
   109  
   110  Make the intervals between messages unpredictable (still under a second).
   111  
   112  .play concurrency/support/lessboring.go /START/,/STOP/
   113  
   114  * Running it
   115  
   116  The boring function runs on forever, like a boring party guest.
   117  
   118  .play concurrency/support/lessboring.go /^func.main/,$
   119  
   120  * Ignoring it
   121  
   122  The go statement runs the function as usual, but doesn't make the caller wait.
   123  
   124  It launches a goroutine.
   125  
   126  The functionality is analogous to the & on the end of a shell command.
   127  
   128  .play concurrency/support/goboring.go 1,/^}/
   129  
   130  * Ignoring it a little less
   131  
   132  When main returns, the program exits and takes the boring function down with it.
   133  
   134  We can hang around a little, and on the way show that both main and the launched goroutine are running.
   135  
   136  .play concurrency/support/waitgoboring.go /func.main/,/^}/
   137  
   138  * Goroutines
   139  
   140  What is a goroutine? It's an independently executing function, launched by a go statement.
   141  
   142  It has its own call stack, which grows and shrinks as required.
   143  
   144  It's very cheap. It's practical to have thousands, even hundreds of thousands of goroutines.
   145  
   146  It's not a thread.
   147  
   148  There might be only one thread in a program with thousands of goroutines.
   149  
   150  Instead, goroutines are multiplexed dynamically onto threads as needed to keep all the goroutines running.
   151  
   152  But if you think of it as a very cheap thread, you won't be far off.
   153  
   154  * Communication
   155  
   156  Our boring examples cheated: the main function couldn't see the output from the other goroutine.
   157  
   158  It was just printed to the screen, where we pretended we saw a conversation.
   159  
   160  Real conversations require communication.
   161  
   162  * Channels
   163  
   164  A channel in Go provides a connection between two goroutines, allowing them to communicate.
   165  
   166  .code concurrency/support/helpers.go /START1/,/STOP1/
   167  .code concurrency/support/helpers.go /START2/,/STOP2/
   168  .code concurrency/support/helpers.go /START3/,/STOP3/
   169  
   170  * Using channels
   171  
   172  A channel connects the main and boring goroutines so they can communicate.
   173  
   174  .play concurrency/support/changoboring.go /START1/,/STOP1/
   175  .code concurrency/support/changoboring.go /START2/,/STOP2/
   176  
   177  * Synchronization
   178  
   179  When the main function executes <–c, it will wait for a value to be sent.
   180  
   181  Similarly, when the boring function executes c <– value, it waits for a receiver to be ready.
   182  
   183  A sender and receiver must both be ready to play their part in the communication. Otherwise we wait until they are.
   184  
   185  Thus channels both communicate and synchronize.
   186  
   187  * An aside about buffered channels
   188  
   189  Note for experts: Go channels can also be created with a buffer.
   190  
   191  Buffering removes synchronization.
   192  
   193  Buffering makes them more like Erlang's mailboxes.
   194  
   195  Buffered channels can be important for some problems but they are more subtle to reason about.
   196  
   197  We won't need them today.
   198  
   199  * The Go approach
   200  
   201  Don't communicate by sharing memory, share memory by communicating.
   202  
   203  * "Patterns"
   204  
   205  * Generator: function that returns a channel
   206  
   207  Channels are first-class values, just like strings or integers.
   208  
   209  .play concurrency/support/generatorboring.go /START1/,/STOP1/
   210  .code concurrency/support/generatorboring.go /START2/,/STOP2/
   211  
   212  * Channels as a handle on a service
   213  
   214  Our boring function returns a channel that lets us communicate with the boring service it provides.
   215  
   216  We can have more instances of the service.
   217  
   218  .play concurrency/support/generator2boring.go /START1/,/STOP1/
   219  
   220  * Multiplexing
   221  
   222  These programs make Joe and Ann count in lockstep.
   223  We can instead use a fan-in function to let whosoever is ready talk.
   224  
   225  .code concurrency/support/faninboring.go /START3/,/STOP3/
   226  .play concurrency/support/faninboring.go /START1/,/STOP1/
   227  
   228  * Fan-in
   229  
   230  .image concurrency/images/gophermegaphones.jpg
   231  
   232  * Restoring sequencing
   233  
   234  Send a channel on a channel, making goroutine wait its turn.
   235  
   236  Receive all messages, then enable them again by sending on a private channel.
   237  
   238  First we define a message type that contains a channel for the reply.
   239  
   240  .code concurrency/support/sequenceboring.go /START0/,/STOP0/
   241  
   242  * Restoring sequencing.
   243  
   244  Each speaker must wait for a go-ahead.
   245  
   246  .code concurrency/support/sequenceboring.go /START1/,/STOP1/
   247  .code concurrency/support/sequenceboring.go /START2/,/STOP2/
   248  .play concurrency/support/sequenceboring.go /START3/,/STOP3/
   249  
   250  * Select
   251  
   252  A control structure unique to concurrency.
   253  
   254  The reason channels and goroutines are built into the language.
   255  
   256  * Select
   257  
   258  The select statement provides another way to handle multiple channels.
   259  It's like a switch, but each case is a communication:
   260  - All channels are evaluated.
   261  - Selection blocks until one communication can proceed, which then does.
   262  - If multiple can proceed, select chooses pseudo-randomly.
   263  - A default clause, if present, executes immediately if no channel is ready.
   264  
   265  .code concurrency/support/select.go /START0/,/STOP0/
   266  
   267  * Fan-in again
   268  
   269  Rewrite our original fanIn function. Only one goroutine is needed. Old:
   270  
   271  .code concurrency/support/faninboring.go /START3/,/STOP3/
   272  
   273  * Fan-in using select
   274  
   275  Rewrite our original fanIn function. Only one goroutine is needed. New:
   276  
   277  .play concurrency/support/selectboring.go /START3/,/STOP3/
   278  
   279  * Timeout using select
   280  
   281  The time.After function returns a channel that blocks for the specified duration.
   282  After the interval, the channel delivers the current time, once.
   283  
   284  .play concurrency/support/timeout.go /START1/,/STOP1/
   285  
   286  * Timeout for whole conversation using select
   287  
   288  Create the timer once, outside the loop, to time out the entire conversation.
   289  (In the previous program, we had a timeout for each message.)
   290  
   291  .play concurrency/support/timeoutall.go /START1/,/STOP1/
   292  
   293  
   294  * Quit channel
   295  
   296  We can turn this around and tell Joe to stop when we're tired of listening to him.
   297  
   298  .code concurrency/support/quit.go /START1/,/STOP1/
   299  .play concurrency/support/quit.go /START2/,/STOP2/
   300  
   301  
   302  * Receive on quit channel
   303  
   304  How do we know it's finished? Wait for it to tell us it's done: receive on the quit channel
   305  
   306  .code concurrency/support/rcvquit.go /START1/,/STOP1/
   307  .play concurrency/support/rcvquit.go /START2/,/STOP2/
   308  
   309  * Daisy-chain
   310  
   311  .play concurrency/support/daisy.go /func/,$
   312  
   313  * Chinese whispers, gopher style
   314  
   315  .image concurrency/images/gophereartrumpet.jpg
   316  
   317  * Systems software
   318  
   319  Go was designed for writing systems software.
   320  Let's see how the concurrency features come into play.
   321  
   322  * Example: Google Search
   323  	
   324  Q: What does Google search do?
   325  
   326  A: Given a query, return a page of search results (and some ads).
   327  
   328  Q: How do we get the search results?
   329  
   330  A: Send the query to Web search, Image search, YouTube, Maps, News,etc., then mix the results.
   331  
   332  How do we implement this?
   333  
   334  * Google Search: A fake framework
   335  
   336  We can simulate the search function, much as we simulated conversation before.
   337  
   338  .code concurrency/support/google.go /START2/,/STOP2/
   339  
   340  * Google Search: Test the framework
   341  
   342  .play concurrency/support/google.go /func.main/,/}/
   343  
   344  * Google Search 1.0
   345  
   346  The Google function takes a query and returns a slice of Results (which are just strings).
   347  
   348  Google invokes Web, Image, and Video searches serially, appending them to the results slice.
   349  
   350  .play concurrency/support/google.go /START1/,/STOP1/
   351  
   352  * Google Search 2.0
   353  
   354  Run the Web, Image, and Video searches concurrently, and wait for all results.
   355  
   356  No locks.  No condition variables.  No callbacks.
   357  
   358  .play concurrency/support/google2.1.go /Google/,/^}/
   359  
   360  * Google Search 2.1
   361  
   362  Don't wait for slow servers. No locks.  No condition variables.  No callbacks.
   363  
   364  .play concurrency/support/google2.2.go /START/,/STOP/
   365  
   366  * Avoid timeout
   367  
   368  Q: How do we avoid discarding results from slow servers?
   369  
   370  A: Replicate the servers.  Send requests to multiple replicas, and use the first response.
   371  
   372  .code concurrency/support/google2.3.go /START1/,/STOP1/
   373  
   374  * Using the First function
   375  
   376  .play concurrency/support/google2.3.go /START2/,/STOP2/
   377  
   378  * Google Search 3.0
   379  
   380  Reduce tail latency using replicated search servers.
   381  
   382  .play concurrency/support/google3.0.go /START/,/STOP/
   383  
   384  * And still…
   385  
   386  No locks.  No condition variables.  No callbacks.
   387  
   388  * Summary
   389  
   390  In just a few simple transformations we used Go's concurrency primitives to convert a
   391  
   392  - slow
   393  - sequential
   394  - failure-sensitive
   395  
   396  program into one that is
   397  
   398  - fast
   399  - concurrent
   400  - replicated
   401  - robust.
   402  
   403  * More party tricks
   404  
   405  There are endless ways to use these tools, many presented elsewhere.
   406  
   407  Chatroulette toy:
   408  
   409  .link http://golang.org/s/chat-roulette
   410  
   411  Load balancer:
   412  
   413  .link http://golang.org/s/load-balancer
   414  
   415  Concurrent prime sieve:
   416  
   417  .link http://golang.org/s/prime-sieve
   418  
   419  Concurrent power series (by McIlroy):
   420  
   421  .link http://golang.org/s/power-series
   422  
   423  * Don't overdo it
   424  
   425  They're fun to play with, but don't overuse these ideas.
   426  
   427  Goroutines and channels are big ideas. They're tools for program construction.
   428  
   429  But sometimes all you need is a reference counter.
   430  
   431  Go has "sync" and "sync/atomic" packages that provide mutexes, condition variables, etc. They provide tools for smaller problems.
   432  
   433  Often, these things will work together to solve a bigger problem.
   434  
   435  Always use the right tool for the job.
   436  
   437  * Conclusions
   438  
   439  Goroutines and channels make it easy to express complex operations dealing with
   440  
   441  - multiple inputs
   442  - multiple outputs
   443  - timeouts
   444  - failure
   445  
   446  And they're fun to use.
   447  
   448  
   449  * Links
   450  
   451  Go Home Page:
   452  
   453  .link http://golang.org
   454  
   455  Go Tour (learn Go in your browser)
   456  
   457  .link http://tour.golang.org
   458  
   459  Package documentation:
   460  
   461  .link http://golang.org/pkg
   462  
   463  Articles galore:
   464  
   465  .link http://golang.org/doc
   466  
   467  Concurrency is not parallelism:
   468  
   469  .link http://golang.org/s/concurrency-is-not-parallelism