
* Update Atomic Counters example to use atomic.Uint64 This commit updates the Atomic Counters example to follow atomic's recommendation of using atomic.Uint64 instead of uint64 (same for other types) and then calling methods on it, instead of calling atomic.AddUint64(). It also updates the comments and empty lines a bit to look better on the website. * Run tools/build again * Fix comments
228 lines
9.7 KiB
Plaintext
Generated
228 lines
9.7 KiB
Plaintext
Generated
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Go by Example: Atomic Counters</title>
|
|
<link rel=stylesheet href="site.css">
|
|
</head>
|
|
<script>
|
|
onkeydown = (e) => {
|
|
|
|
if (e.key == "ArrowLeft") {
|
|
window.location.href = 'rate-limiting';
|
|
}
|
|
|
|
|
|
if (e.key == "ArrowRight") {
|
|
window.location.href = 'mutexes';
|
|
}
|
|
|
|
}
|
|
</script>
|
|
<body>
|
|
<div class="example" id="atomic-counters">
|
|
<h2><a href="./">Go by Example</a>: Atomic Counters</h2>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>The primary mechanism for managing state in Go is
|
|
communication over channels. We saw this for example
|
|
with <a href="worker-pools">worker pools</a>. There are a few other
|
|
options for managing state though. Here we’ll
|
|
look at using the <code>sync/atomic</code> package for <em>atomic
|
|
counters</em> accessed by multiple goroutines.</p>
|
|
|
|
</td>
|
|
<td class="code empty leading">
|
|
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
<a href="https://go.dev/play/p/LfAMxMppwL-"><img title="Run code" src="play.png" class="run" /></a><img title="Copy code" src="clipboard.png" class="copy" />
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="s">"sync"</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="s">"sync/atomic"</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>We’ll use an atomic integer type to represent our
|
|
(always-positive) counter.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">ops</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">Uint64</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>A WaitGroup will help us wait for all goroutines
|
|
to finish their work.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">wg</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>We’ll start 50 goroutines that each increment the
|
|
counter exactly 1000 times.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="mi">50</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <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></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">c</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">c</span> <span class="p"><</span> <span class="mi">1000</span><span class="p">;</span> <span class="nx">c</span><span class="o">++</span> <span class="p">{</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>To atomically increment the counter we use <code>Add</code>.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">ops</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Done</span><span class="p">()</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}()</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>Wait until all the goroutines are done.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>Reading atomics safely while they are being updated is
|
|
possible using functions like <code>Load</code>, although here it’s
|
|
safe anyway, because no goroutines are writing to ‘ops’.</p>
|
|
|
|
</td>
|
|
<td class="code">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"ops:"</span><span class="p">,</span> <span class="nx">ops</span><span class="p">.</span><span class="nf">Load</span><span class="p">())</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>We expect to get exactly 50,000 operations. Had we
|
|
used the non-atomic <code>ops++</code> to increment the counter,
|
|
we’d likely get a different number, changing between
|
|
runs, because the goroutines would interfere with
|
|
each other. Moreover, we’d get data race failures
|
|
when running with the <code>-race</code> flag.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="gp">$</span> go run atomic-counters.go
|
|
</span></span><span class="line"><span class="cl"><span class="go">ops: 50000</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>Next we’ll look at mutexes, another tool for managing
|
|
state.</p>
|
|
|
|
</td>
|
|
<td class="code empty">
|
|
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
<p class="next">
|
|
Next example: <a href="mutexes">Mutexes</a>.
|
|
</p>
|
|
|
|
|
|
<p class="footer">
|
|
by <a href="https://markmcgranaghan.com">Mark McGranaghan</a> and <a href="https://eli.thegreenplace.net">Eli Bendersky</a> | <a href="https://github.com/mmcgrana/gobyexample">source</a> | <a href="https://github.com/mmcgrana/gobyexample#license">license</a>
|
|
</p>
|
|
|
|
</div>
|
|
<script>
|
|
var codeLines = [];
|
|
codeLines.push('');codeLines.push('package main\u000A');codeLines.push('import (\u000A \"fmt\"\u000A \"sync\"\u000A \"sync/atomic\"\u000A)\u000A');codeLines.push('func main() {\u000A');codeLines.push(' var ops atomic.Uint64\u000A');codeLines.push(' var wg sync.WaitGroup\u000A');codeLines.push(' for i :\u003D 0; i \u003C 50; i++ {\u000A wg.Add(1)\u000A');codeLines.push(' go func() {\u000A for c :\u003D 0; c \u003C 1000; c++ {\u000A');codeLines.push(' ops.Add(1)\u000A }\u000A');codeLines.push(' wg.Done()\u000A }()\u000A }\u000A');codeLines.push(' wg.Wait()\u000A');codeLines.push(' fmt.Println(\"ops:\", ops.Load())\u000A}\u000A');codeLines.push('');codeLines.push('');
|
|
</script>
|
|
<script src="site.js" async></script>
|
|
</body>
|
|
</html>
|