Concurrency in golang

238 86 0
Concurrency in golang

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Sách về golang rất hay và bổ ích. Qua cuốn sách này bạn sẽ học thêm về cách xử lý đa luồng trong golang rất có ích cho công việc của bạn sau này. Golang đã và đang là cơn sốt của cộng đồng lập trình viên.

Concurrency in Go TOOLS & TECHNIQUES FOR DEVELOPERS Katherine Cox-Buday www.allitebooks.com www.allitebooks.com Concurrency in Go Tools and Techniques for Developers Katherine Cox-Buday Beijing Boston Farnham Sebastopol www.allitebooks.com Tokyo Concurrency in Go by Katherine Cox-Buday Copyright © 2017 Katherine Cox-Buday All rights reserved Printed in the United States of America Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472 O’Reilly books may be purchased for educational, business, or sales promotional use Online editions are also available for most titles (http://oreilly.com/safari) For more information, contact our corporate/insti‐ tutional sales department: 800-998-9938 or corporate@oreilly.com Editor: Dawn Schanafelt Production Editor: Nicholas Adams Copyeditor: Kim Cofer Proofreader: Sonia Saruba Indexer: Judy McConville Interior Designer: David Futato Cover Designer: Karen Montgomery Illustrator: Rebecca Demarest First Edition August 2017: Revision History for the First Edition 2017-07-18: First Release See http://oreilly.com/catalog/errata.csp?isbn=9781491941195 for release details The O’Reilly logo is a registered trademark of O’Reilly Media, Inc Concurrency in Go, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work Use of the information and instructions contained in this work is at your own risk If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights 978-1-491-94119-5 [LSI] www.allitebooks.com For L and N whose sacrifice made this book possible Of everything in my life, you are the best I love you www.allitebooks.com www.allitebooks.com Table of Contents Preface vii An Introduction to Concurrency Moore’s Law, Web Scale, and the Mess We’re In Why Is Concurrency Hard? Race Conditions Atomicity Memory Access Synchronization Deadlocks, Livelocks, and Starvation Determining Concurrency Safety Simplicity in the Face of Complexity 4 10 18 20 Modeling Your Code: Communicating Sequential Processes 23 The Difference Between Concurrency and Parallelism What Is CSP? How This Helps You Go’s Philosophy on Concurrency 23 26 29 31 Go’s Concurrency Building Blocks 37 Goroutines The sync Package WaitGroup Mutex and RWMutex Cond Once Pool Channels The select Statement 37 47 47 49 52 57 59 64 78 v www.allitebooks.com The GOMAXPROCS Lever Conclusion 83 83 Concurrency Patterns in Go 85 Confinement The for-select Loop Preventing Goroutine Leaks The or-channel Error Handling Pipelines Best Practices for Constructing Pipelines Some Handy Generators Fan-Out, Fan-In The or-done-channel The tee-channel The bridge-channel Queuing The context Package Summary 85 89 90 94 97 100 104 109 114 119 120 122 124 131 145 Concurrency at Scale 147 Error Propagation Timeouts and Cancellation Heartbeats Replicated Requests Rate Limiting Healing Unhealthy Goroutines Summary 147 155 161 172 174 188 194 Goroutines and the Go Runtime 197 Work Stealing Stealing Tasks or Continuations? Presenting All of This to the Developer Conclusion 197 204 212 212 A Appendix 213 Index 219 vi | Table of Contents www.allitebooks.com Preface Hey, welcome to Concurrency in Go! I’m delighted that you’ve picked up this book and excited to join you in exploring the topic of concurrency in Go over the next six chapters! Go is a wonderful language When it was first announced and birthed into the world, I remember exploring it with great interest: it was terse, compiled incredibly fast, per‐ formed well, supported duck typing, and—to my delight—I found working with its concurrency primitives to be intuitive The first time I used the go keyword to create a goroutine (something we’ll cover, I promise!) I got this silly grin on my face I had worked with concurrency in several languages, but I had never worked in a language that made concurrency so easy (which is not to say they don’t exist; I just hadn’t used any) I had found my way to Go Over the years I moved from writing personal scripts in Go, to personal projects, until I found myself working on a many-hundreds-of-thousands-of-lines project pro‐ fessionally Along the way the community was growing with the language, and we were collectively discovering best practices for working with concurrency in Go A few people gave talks on patterns they had discovered But there still weren’t many comprehensive guides on how to wield concurrency in Go in the community It was with this in mind that I set out to write this book I wanted the community to have access to high-quality and comprehensive information about concurrency in Go: how to use it, best practices and patterns for incorporating it into your systems, and how it all works under the covers I have done my best to strike a balance between these concerns I hope this book proves useful! vii www.allitebooks.com Who Should Read This Book This book is meant for developers who have some experience with Go; I make no attempt to explain the basic syntax of the language Knowledge of how concurrency is presented in other languages is useful, but not necessary By the end of this book we will have discussed the entire stack of Go concurrency concerns: common concurrency pitfalls, motivation behind the design of Go’s con‐ currency, the basic syntax of Go’s concurrency primitives, common concurrency pat‐ terns, patterns of patterns, and various tooling that will help you along the way Because of the breadth of topics we’ll cover, this book will be useful to various crosssections of people The next section will help you navigate this book depending on what needs you have Navigating This Book When I read technical books, I usually hop around to the areas that pique my inter‐ est Or, if I’m trying to ramp up on a new technology for work, I frantically skim for the bits that are immediately relevant to my work Whatever your use case is, here’s a roadmap for the book with the hopes that it help guide you to where you need to be! Chapter 1, An Introduction to Concurrency This chapter will give you a broad historical perspective on why concurrency is an important concept, and also discuss some of the fundamental problems that make concurrency difficult to get correct It also briefly touches on how Go helps ease some of this burden If you have a working knowledge of concurrency or just want to get to the tech‐ nical aspects of how to use Go’s concurrency primitives, it’s safe to skip this chapter Chapter 2, Modeling Your Code: Communicating Sequential Processes This chapter deals with some of the motivational factors that contributed to Go’s design This will help give you some context for conversations with others in the Go community and help to frame your understanding of why things work the way they in the language Chapter 3, Go’s Concurrency Building Blocks Here we’ll start to dig into the syntax of Go’s concurrency primitives We’ll also cover the sync package, which is responsible for handling Go’s memory access synchronization If you haven’t used concurrency within Go before and are look‐ ing to hop right in, this is the place to start viii | Preface www.allitebooks.com goroutine As you can see from the following table, stealing continuations has several benefits: Queue Size Continuation Bounded Child Unbounded Order of Execution Serial Out of Order Join Point Nonstalling Stalling So why don’t all work-stealing algorithms implement continuation stealing? Well, continuation stealing usually requires support from the compiler Luckily, Go has its own compiler, and continuation stealing is how Go’s work-stealing algorithm is implemented Languages that don’t have this luxury usually implement task, or socalled “child,” stealing as a library While this model is closer to Go’s algorithm, it still doesn’t represent the entire pic‐ ture Go performs additional optimizations Before we analyze those, let’s set the stage by starting to use the Go scheduler’s nomenclature as laid out in the source code Go’s scheduler has three main concepts: G M P A goroutine An OS thread (also referenced as a machine in the source code) A context (also referenced as a processor in the source code) In our discussion about work stealing, M is equivalent to T, and P is equivalent to the work deque (changing GOMAXPROCS changes how many of these are allocated) The G is a goroutine, but keep in mind it represents the current state of a goroutine, most notably its program counter (PC) This allows a G to represent a continuation so Go can continuation stealing In Go’s runtime, Ms are started, which then host Ps, which then schedule and host Gs: 210 | Chapter 6: Goroutines and the Go Runtime Personally, I find it difficult to follow analysis of how this algorithm works when only this notation is used, so I’ll be using their full names in this analysis Alright, now that we have our terms down, let’s take a look at how Go’s scheduler works! As we mentioned, the GOMAXPROCS setting controls how many contexts are available for use by the runtime The default setting is for there to be one context per logical CPU on the host machine Unlike contexts, there may be more or less OS threads than cores to help Go’s runtime manage things like garbage collection and goroutines I bring this up because there is one very important guarantee in the runtime: there will always be at least enough OS threads available to handle hosting every context This allows the runtime to make an important optimization The runtime also con‐ tains a thread pool for threads that aren’t currently being utilized Now let’s talk about those optimizations! Consider what would happen if any of the goroutines were blocked either by input/ output or by making a system call outside of Go’s runtime The OS thread that hosts the goroutine would also be blocked and would be unable to make progress or host any other goroutines Logically, this is just fine, but from a performance perspective, Go could more to keep processors on the machine as active as possible What Go does in this situation is dissociate the context from the OS thread so that the context can be handed off to another, unblocked, OS thread This allows the context to schedule further goroutines, which allows the runtime to keep the host machine’s CPUs active The blocked goroutine remains associated with the blocked thread When the goroutine eventually becomes unblocked, the host OS thread attempts to steal back a context from one of the other OS threads so that it can continue execut‐ ing the previously blocked goroutine However, sometimes this is not always possible In this case, the thread will place its goroutine on a global context, the thread will go to sleep, and it will be put into the runtime’s thread pool for future use (for instance, if a goroutine becomes blocked again) The global context we just mentioned doesn’t fit into our prior discussions of abstract work-stealing algorithms It’s an implementation detail that is necessitated by how Go is optimizing CPU utilization To ensure that goroutines placed into the global con‐ text aren’t there perpetually, a few extra steps are added into the work-stealing algo‐ rithm Periodically, a context will check the global context to see if there are any goroutines there, and when a context’s queue is empty, it will first check the global context for work to steal before checking other OS threads’ contexts Other than input/output and system calls, Go also allows goroutines to be preempted during any function call This works in tandem with Go’s philosophy of preferring very fine-grained concurrent tasks by ensuring the runtime can efficiently schedule work One notable exception that the team has been trying to solve is goroutines that perform no input/output, system calls, or function calls Currently, these kinds of Work Stealing | 211 goroutines are not preemptable and can cause significant issues like long GC waits, or even deadlocks Fortunately, from an anecdotal perspective, this is a vanishingly small occurrence Presenting All of This to the Developer Now that you understand how goroutines work under the covers, let’s once again pull back and reiterate how developers interface with all of this: the go keyword That’s it! Slap the word go before a function or closure, and you’ve automatically scheduled a task that will be run in the most efficient way for the machine it’s running on As developers, we’re still thinking in the primitives we’re familiar with: functions We don’t have to understand a new way of doing things, complicated data structures, or scheduling algorithms Scaling, efficiency, and simplicity This is what makes goroutines so intriguing Conclusion We’ve now traversed the entire landscape of concurrency in Go: from first principles, to basic usage, to patterns, and how the runtime does things I sincerely hope this book has given you a good grasp of concurrency in Go and aids you in completing all your glorious hacks Thank you! 212 | Chapter 6: Goroutines and the Go Runtime Appendix As you set forth on your journey of writing concurrent code, you’ll need the tools to write your program and analyze it for correctness, and a few helpful pointers to help you understand what’s happening within your programs Lucky for you, the Go eco‐ system has a rich set of tooling both from the Go team and from the community! This appendix will discuss some of these tools and how they can aid you before, dur‐ ing, and after development Since this book is focused on concurrency, I’m going to constrain the conversation to only topics that help you write or analyze concurrent code We’ll also briefly look at what happens when goroutines panic It doesn’t happen often, but the output can be a bit confusing the first time you see it Anatomy of a Goroutine Error It happens to the best of us: sooner or later, your program will panic If you’re lucky, no humans or computers will be harmed in the process, and the worst that will hap‐ pen is you’ll be staring down the bad end of a stack trace Prior to Go 1.6, when a goroutine panicked, the runtime would print stack traces of all the currently executing goroutines Sometimes this made it difficult (or at least time-consuming) to determine what had happened At the time of this writing, Go 1.6 and greater greatly simplify things by printing only the stack trace of the panick‐ ing goroutine For example, when this simple program is executed: package main func main() { waitForever := make(chan interface{}) go func() { panic("test panic") }()

Ngày đăng: 25/05/2020, 01:29

Từ khóa liên quan

Mục lục

  • Copyright

  • Table of Contents

  • Preface

    • Who Should Read This Book

    • Navigating This Book

    • Online Resources

    • Conventions Used in This Book

    • Using Code Examples

    • O’Reilly Safari

    • How to Contact Us

    • Acknowledgments

    • Chapter 1. An Introduction to Concurrency

      • Moore’s Law, Web Scale, and the Mess We’re In

      • Why Is Concurrency Hard?

        • Race Conditions

        • Atomicity

        • Memory Access Synchronization

        • Deadlocks, Livelocks, and Starvation

        • Determining Concurrency Safety

        • Simplicity in the Face of Complexity

        • Chapter 2. Modeling Your Code: Communicating Sequential Processes

          • The Difference Between Concurrency and Parallelism

          • What Is CSP?

          • How This Helps You

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan