diff options
Diffstat (limited to 'content/codelab-share.article')
-rw-r--r-- | content/codelab-share.article | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/content/codelab-share.article b/content/codelab-share.article new file mode 100644 index 0000000..03fbab6 --- /dev/null +++ b/content/codelab-share.article @@ -0,0 +1,107 @@ +# Share Memory By Communicating +13 Jul 2010 +Tags: concurrency, technical +Summary: A preview of the new Go codelab, Share Memory by Communicating. +OldURL: /share-memory-by-communicating + +Andrew Gerrand + +## + +Traditional threading models (commonly used when writing Java, +C++, and Python programs, for example) require the programmer to communicate +between threads using shared memory. +Typically, shared data structures are protected by locks, +and threads will contend over those locks to access the data. +In some cases, this is made easier by the use of thread-safe data structures +such as Python's Queue. + +Go's concurrency primitives - goroutines and channels - provide an elegant +and distinct means of structuring concurrent software. +(These concepts have an [interesting history](https://swtch.com/~rsc/thread/) that begins with C. +A. R. Hoare's [Communicating Sequential Processes](http://www.usingcsp.com/).) +Instead of explicitly using locks to mediate access to shared data, +Go encourages the use of channels to pass references to data between goroutines. +This approach ensures that only one goroutine has access to the data at a given time. +The concept is summarized in the document [Effective Go](https://golang.org/doc/effective_go.html) +(a must-read for any Go programmer): + +_Do not communicate by sharing memory; instead, share memory by communicating._ + +Consider a program that polls a list of URLs. +In a traditional threading environment, one might structure its data like so: + + type Resource struct { + url string + polling bool + lastPolled int64 + } + + type Resources struct { + data []*Resource + lock *sync.Mutex + } + +And then a Poller function (many of which would run in separate threads) might look something like this: + + func Poller(res *Resources) { + for { + // get the least recently-polled Resource + // and mark it as being polled + res.lock.Lock() + var r *Resource + for _, v := range res.data { + if v.polling { + continue + } + if r == nil || v.lastPolled < r.lastPolled { + r = v + } + } + if r != nil { + r.polling = true + } + res.lock.Unlock() + if r == nil { + continue + } + + // poll the URL + + // update the Resource's polling and lastPolled + res.lock.Lock() + r.polling = false + r.lastPolled = time.Nanoseconds() + res.lock.Unlock() + } + } + +This function is about a page long, and requires more detail to make it complete. +It doesn't even include the URL polling logic (which, +itself, would only be a few lines), nor will it gracefully handle exhausting +the pool of Resources. + +Let's take a look at the same functionality implemented using Go idiom. +In this example, Poller is a function that receives Resources to be polled +from an input channel, +and sends them to an output channel when they're done. + + type Resource string + + func Poller(in, out chan *Resource) { + for r := range in { + // poll the URL + + // send the processed Resource to out + out <- r + } + } + +The delicate logic from the previous example is conspicuously absent, +and our Resource data structure no longer contains bookkeeping data. +In fact, all that's left are the important parts. +This should give you an inkling as to the power of these simple language features. + +There are many omissions from the above code snippets. +For a walkthrough of a complete, idiomatic Go program that uses these ideas, +see the Codewalk [_Share Memory By Communicating_](https://golang.org/doc/codewalk/sharemem/). |