]> Cypherpunks repositories - gostls13.git/commitdiff
start the concurrency discussion. work from the outside in because this is a toughie.
authorRob Pike <r@golang.org>
Tue, 20 Oct 2009 19:30:39 +0000 (12:30 -0700)
committerRob Pike <r@golang.org>
Tue, 20 Oct 2009 19:30:39 +0000 (12:30 -0700)
also fix a pedantry in the language design faq.

R=rsc
DELTA=113  (94 added, 16 deleted, 3 changed)
OCL=35922
CL=35928

doc/effective_go.html
doc/go_lang_faq.html

index 0efd224a768e73e5f23d2634fbfb2f68be9c0907..23eaf3ce7831b4546625d1da849b826fd9dcafa7 100644 (file)
@@ -1,7 +1,5 @@
 <!-- Effective Go -->
 
-<!-- testing?; concurrency; initialization-->
-
 <h2 id="introduction">Introduction</h2>
 
 <p>
@@ -194,7 +192,7 @@ If the package is simple, the package comment can be brief.
 <p>
 Comments do not need extra formatting such as banners of stars.
 The generated output may not even be presented in a fixed-width font, so don't depend
-on spacing for alignment<code>godoc</code>, like <code>gofmt</code>,
+on spacing for alignment&mdash;<code>godoc</code>, like <code>gofmt</code>,
 takes care of that.
 Finally, the comments are uninterpreted plain text, so HTML and other
 annotations such as <code>_this_</code> will reproduce <i>verbatim</i> and should
@@ -830,7 +828,7 @@ func NewFile(fd int, name string) *File {
 </pre>
 
 <p>
-There's a lot of boilerplate in there.  We can simplify it
+There's a lot of boiler plate in there.  We can simplify it
 using a <i>composite literal</i>, which is
 an expression that creates a
 new instance each time it is evaluated.
@@ -1838,6 +1836,100 @@ is never used.
 </p>
 
 
+<h2 id="concurrency">Concurrency</h2>
+
+<h3 id="sharing">Share by communicating</h3>
+
+<p>
+Concurrent programming in many environments is made difficult by the
+subtleties required to implement correct access to shared variables.  Go encourages
+a different approach in which shared values are passed around on channels
+and, in fact, never actively shared by separate threads of execution.
+Only one goroutine has access to the value at any given time.
+Data races cannot occur, by design.
+To encourage this way of thinking we have reduced it to a slogan:
+</p>
+<blockquote>
+Do not communicate by sharing memory;
+instead, share memory by communicating.
+</blockquote>
+<p>
+This approach can be taken too far.  Reference counts may be best done
+by putting a mutex around an integer variable, for instance.  But as a
+high-level approach, using channels to control access makes it easier
+to write clear, correct programs.
+</p>
+<p>
+Another way to think about this model is to consider a typical single-threaded
+program running on one CPU. It has no need for synchronization primitives.
+Now run another such instance; it too needs no synchronization.  Now let those
+two communicate; if the communication is the synchronizer, there's still no need
+for other synchronization.  Consider Unix pipelines: they fit this model just
+fine.  Although Go's approach to concurrency originates in Hoare's
+Communicating Sequential Processes (CSP),
+it can also be seen as a type-safe generalization of Unix pipes.
+</p>
+
+<h3 id="goroutines">Goroutines</h3>
+
+<h3 id="channels">Channels</h3>
+
+<h3 id="leaky_buffer">A leaky buffer</h3>
+
+<p>
+The tools of concurrent programming can often make non-concurrent
+ideas easier to express.  Here's an example abstracted from an RPC
+package.  The client goroutine loops receiving data from some source,
+perhaps a network.  To avoid allocating and freeing buffers, it keeps
+a free list, and uses a buffered channel to represent it.  If the
+channel is empty, a new buffer gets allocated.
+Once the message buffer is ready, it's sent to the server on
+<code>serverChan</code>.
+</p>
+<pre>
+var freelist = make(chan *Buffer, 100)
+var server_chan = make(chan *Buffer)
+
+func client() {
+       for {
+               b, ok := <-freeList;  // grab one if available
+               if !ok {              // free list empty; allocate a new buffer
+                       b = new(Buffer)
+               }
+               load(b);              // grab the next message, perhaps from the net
+               serverChan <- b;      // send to server
+       }
+}
+</pre>
+<p>
+The server loop receives messages from the client, processes them,
+and returns the buffer to the free list.
+</p>
+<pre>
+func server() {
+       for {
+               b := <-serverChan;    // wait for work
+               process(b);
+               _ = freeList <- b;    // reuse buffer if room
+       }
+}
+</pre>
+<p>
+The client's non-blocking receive from <code>freeList</code> obtains a
+buffer if one is available; otherwise the client allocates
+a fresh one.
+The server's non-blocking send on freeList puts <code>b</code> back
+on the free list unless the list is full, in which case the
+buffer is dropped on the floor to be reclaimed by
+the garbage collector.
+(The assignment of the send operation to the blank identifier
+makes it non-blocking but ignores whether
+the operation succeeded.)
+This implementation builds a leaky bucket free list
+in just a few lines, relying on the buffered channel and
+the garbage collector for bookkeeping.
+</p>
+
 <h2 id="errors">Errors</h2>
 
 <p>
@@ -1933,20 +2025,6 @@ template
 eventually datafmt
 </p>
 
-<h2>Concurrency</h2>
-
-<h3 id="share-memory">Share memory by communicating</h3>
-
-<p>
-Do not communicate by sharing memory;
-instead, share memory by communicating.
-</p>
-
-<p>
-XXX, more here.
-</p>
-
-
 <h2>Testing</h2>
 
 <h3 id="no-abort">Run tests to completion</h3>
index 21466437ffd3a63bbdb39e6e680fcd6e2e840e7c..a6d1d670ba651449d5f6f2aba1b679e9e99b3d89 100644 (file)
@@ -167,7 +167,7 @@ issues around order of evaluation of <code>++</code> and <code>--</code>
 are eliminated as well.  The simplification is
 significant.  As for postfix vs. prefix, either would work fine but
 the postfix version is more traditional; insistence on prefix arose
-with the STL, part of a language whose name contains, ironically, a
+with the STL, a library for a language whose name contains, ironically, a
 postfix increment.
 </p>