Rewrite the WaitGroup example to be more idiomatic
A wrapper closure invokes wg.Done Still mention the pass-by-pointer requirements on the WaitGroup Fixes #278
This commit is contained in:
parent
4de485a514
commit
b1ef499821
@ -10,12 +10,7 @@ import (
|
||||
)
|
||||
|
||||
// This is the function we'll run in every goroutine.
|
||||
// Note that a WaitGroup must be passed to functions by
|
||||
// pointer.
|
||||
func worker(id int, wg *sync.WaitGroup) {
|
||||
// On return, notify the WaitGroup that we're done.
|
||||
defer wg.Done()
|
||||
|
||||
func worker(id int) {
|
||||
fmt.Printf("Worker %d starting\n", id)
|
||||
|
||||
// Sleep to simulate an expensive task.
|
||||
@ -26,14 +21,29 @@ func worker(id int, wg *sync.WaitGroup) {
|
||||
func main() {
|
||||
|
||||
// This WaitGroup is used to wait for all the
|
||||
// goroutines launched here to finish.
|
||||
// goroutines launched here to finish. Note: if a WaitGroup is
|
||||
// explicitly passed into functions, it should be done *by pointer*.
|
||||
// This would be important if, for example, our worker had to launch
|
||||
// additional goroutines.
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Launch several goroutines and increment the WaitGroup
|
||||
// counter for each.
|
||||
for i := 1; i <= 5; i++ {
|
||||
wg.Add(1)
|
||||
go worker(i, &wg)
|
||||
// Avoid re-use of the same `i` value in each goroutine closure.
|
||||
// See [the FAQ](https://golang.org/doc/faq#closures_and_goroutines)
|
||||
// for more details.
|
||||
i := i
|
||||
|
||||
// Wrap the worker call in a closure that makes sure to tell
|
||||
// the WaitGroup that this worker is done. This way the worker
|
||||
// itself does not have to be aware of the concurrency primitives
|
||||
// involved in its execution.
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
worker(i)
|
||||
}()
|
||||
}
|
||||
|
||||
// Block until the WaitGroup counter goes back to 0;
|
||||
|
@ -1,2 +1,2 @@
|
||||
b87ababcf7e1ce54107252c658840097bb6060a7
|
||||
vXBl8zQpDYj
|
||||
58031ceb701a1cab27498efd89adadbf1ea6b3e6
|
||||
vmjCBfN6MJE
|
||||
|
75
public/waitgroups
generated
75
public/waitgroups
generated
@ -42,7 +42,7 @@ use a <em>wait group</em>.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
<a href="http://play.golang.org/p/vXBl8zQpDYj"><img title="Run code" src="play.png" class="run" /></a><img title="Copy code" src="clipboard.png" class="copy" />
|
||||
<a href="http://play.golang.org/p/vmjCBfN6MJE"><img title="Run code" src="play.png" class="run" /></a><img title="Copy code" src="clipboard.png" class="copy" />
|
||||
<pre class="chroma"><span class="kn">package</span> <span class="nx">main</span>
|
||||
</pre>
|
||||
</td>
|
||||
@ -65,39 +65,14 @@ use a <em>wait group</em>.</p>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>This is the function we’ll run in every goroutine.
|
||||
Note that a WaitGroup must be passed to functions by
|
||||
pointer.</p>
|
||||
<p>This is the function we’ll run in every goroutine.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="kd">func</span> <span class="nf">worker</span><span class="p">(</span><span class="nx">id</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">wg</span> <span class="o">*</span><span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span><span class="p">)</span> <span class="p">{</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>On return, notify the WaitGroup that we’re done.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="k">defer</span> <span class="nx">wg</span><span class="p">.</span><span class="nf">Done</span><span class="p">()</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Worker %d starting\n"</span><span class="p">,</span> <span class="nx">id</span><span class="p">)</span>
|
||||
<span class="kd">func</span> <span class="nf">worker</span><span class="p">(</span><span class="nx">id</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Worker %d starting\n"</span><span class="p">,</span> <span class="nx">id</span><span class="p">)</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
@ -131,7 +106,10 @@ pointer.</p>
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>This WaitGroup is used to wait for all the
|
||||
goroutines launched here to finish.</p>
|
||||
goroutines launched here to finish. Note: if a WaitGroup is
|
||||
explicitly passed into functions, it should be done <em>by pointer</em>.
|
||||
This would be important if, for example, our worker had to launch
|
||||
additional goroutines.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
@ -153,7 +131,40 @@ counter for each.</p>
|
||||
<pre class="chroma">
|
||||
<span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><=</span> <span class="mi">5</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
|
||||
<span class="nx">wg</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||||
<span class="k">go</span> <span class="nf">worker</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="o">&</span><span class="nx">wg</span><span class="p">)</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>Avoid re-use of the same <code>i</code> value in each goroutine closure.
|
||||
See <a href="https://golang.org/doc/faq#closures_and_goroutines">the FAQ</a>
|
||||
for more details.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="nx">i</span> <span class="o">:=</span> <span class="nx">i</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>Wrap the worker call in a closure that makes sure to tell
|
||||
the WaitGroup that this worker is done. This way the worker
|
||||
itself does not have to be aware of the concurrency primitives
|
||||
involved in its execution.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
|
||||
<span class="k">defer</span> <span class="nx">wg</span><span class="p">.</span><span class="nf">Done</span><span class="p">()</span>
|
||||
<span class="nf">worker</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span>
|
||||
<span class="p">}()</span>
|
||||
<span class="p">}</span>
|
||||
</pre>
|
||||
</td>
|
||||
@ -240,7 +251,7 @@ is likely to be different for each invocation.</p>
|
||||
</div>
|
||||
<script>
|
||||
var codeLines = [];
|
||||
codeLines.push('');codeLines.push('package main\u000A');codeLines.push('import (\u000A \"fmt\"\u000A \"sync\"\u000A \"time\"\u000A)\u000A');codeLines.push('func worker(id int, wg *sync.WaitGroup) {\u000A');codeLines.push(' defer wg.Done()\u000A');codeLines.push(' fmt.Printf(\"Worker %d starting\\n\", id)\u000A');codeLines.push(' time.Sleep(time.Second)\u000A fmt.Printf(\"Worker %d done\\n\", id)\u000A}\u000A');codeLines.push('func main() {\u000A');codeLines.push(' var wg sync.WaitGroup\u000A');codeLines.push(' for i :\u003D 1; i \u003C\u003D 5; i++ {\u000A wg.Add(1)\u000A go worker(i, \u0026wg)\u000A }\u000A');codeLines.push(' wg.Wait()\u000A');codeLines.push('}\u000A');codeLines.push('');codeLines.push('');
|
||||
codeLines.push('');codeLines.push('package main\u000A');codeLines.push('import (\u000A \"fmt\"\u000A \"sync\"\u000A \"time\"\u000A)\u000A');codeLines.push('func worker(id int) {\u000A fmt.Printf(\"Worker %d starting\\n\", id)\u000A');codeLines.push(' time.Sleep(time.Second)\u000A fmt.Printf(\"Worker %d done\\n\", id)\u000A}\u000A');codeLines.push('func main() {\u000A');codeLines.push(' var wg sync.WaitGroup\u000A');codeLines.push(' for i :\u003D 1; i \u003C\u003D 5; i++ {\u000A wg.Add(1)\u000A');codeLines.push(' i :\u003D i\u000A');codeLines.push(' go func() {\u000A defer wg.Done()\u000A worker(i)\u000A }()\u000A }\u000A');codeLines.push(' wg.Wait()\u000A');codeLines.push('}\u000A');codeLines.push('');codeLines.push('');
|
||||
</script>
|
||||
<script src="site.js" async></script>
|
||||
</body>
|
||||
|
Loading…
x
Reference in New Issue
Block a user