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.
|
// This is the function we'll run in every goroutine.
|
||||||
// Note that a WaitGroup must be passed to functions by
|
func worker(id int) {
|
||||||
// pointer.
|
|
||||||
func worker(id int, wg *sync.WaitGroup) {
|
|
||||||
// On return, notify the WaitGroup that we're done.
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
fmt.Printf("Worker %d starting\n", id)
|
fmt.Printf("Worker %d starting\n", id)
|
||||||
|
|
||||||
// Sleep to simulate an expensive task.
|
// Sleep to simulate an expensive task.
|
||||||
@ -26,14 +21,29 @@ func worker(id int, wg *sync.WaitGroup) {
|
|||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
// This WaitGroup is used to wait for all the
|
// 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
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
// Launch several goroutines and increment the WaitGroup
|
// Launch several goroutines and increment the WaitGroup
|
||||||
// counter for each.
|
// counter for each.
|
||||||
for i := 1; i <= 5; i++ {
|
for i := 1; i <= 5; i++ {
|
||||||
wg.Add(1)
|
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;
|
// Block until the WaitGroup counter goes back to 0;
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
b87ababcf7e1ce54107252c658840097bb6060a7
|
58031ceb701a1cab27498efd89adadbf1ea6b3e6
|
||||||
vXBl8zQpDYj
|
vmjCBfN6MJE
|
||||||
|
75
public/waitgroups
generated
75
public/waitgroups
generated
@ -42,7 +42,7 @@ use a <em>wait group</em>.</p>
|
|||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td class="code leading">
|
<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 class="chroma"><span class="kn">package</span> <span class="nx">main</span>
|
||||||
</pre>
|
</pre>
|
||||||
</td>
|
</td>
|
||||||
@ -65,39 +65,14 @@ use a <em>wait group</em>.</p>
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="docs">
|
<td class="docs">
|
||||||
<p>This is the function we’ll run in every goroutine.
|
<p>This is the function we’ll run in every goroutine.</p>
|
||||||
Note that a WaitGroup must be passed to functions by
|
|
||||||
pointer.</p>
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td class="code leading">
|
<td class="code leading">
|
||||||
|
|
||||||
<pre class="chroma">
|
<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>
|
<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>
|
||||||
</pre>
|
<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>
|
||||||
</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>
|
|
||||||
</pre>
|
</pre>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -131,7 +106,10 @@ pointer.</p>
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="docs">
|
<td class="docs">
|
||||||
<p>This WaitGroup is used to wait for all the
|
<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>
|
||||||
<td class="code leading">
|
<td class="code leading">
|
||||||
@ -153,7 +131,40 @@ counter for each.</p>
|
|||||||
<pre class="chroma">
|
<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="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="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>
|
<span class="p">}</span>
|
||||||
</pre>
|
</pre>
|
||||||
</td>
|
</td>
|
||||||
@ -240,7 +251,7 @@ is likely to be different for each invocation.</p>
|
|||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
var codeLines = [];
|
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>
|
||||||
<script src="site.js" async></script>
|
<script src="site.js" async></script>
|
||||||
</body>
|
</body>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user