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