Consistently use Sleep in state-management examples

Consistently use `time.Sleep`, instead of `runtime.Gosched`, to ensure all
goroutines can make progress. `Gosched` wasn't working in the playground
(ref #149).

Also stop trying to compare operation rates. This was tenuous given e.g. how
short the programs ran for, and with the `Sleep`s we now expect the rates to
be similar anyways.
This commit is contained in:
Mark McGranaghan 2016-12-27 08:56:49 -08:00
parent 94cba6875d
commit 6a58750728
12 changed files with 87 additions and 85 deletions

View File

@ -10,7 +10,6 @@ package main
import "fmt" import "fmt"
import "time" import "time"
import "sync/atomic" import "sync/atomic"
import "runtime"
func main() { func main() {
@ -30,8 +29,8 @@ func main() {
// `&` syntax. // `&` syntax.
atomic.AddUint64(&ops, 1) atomic.AddUint64(&ops, 1)
// Allow other goroutines to proceed. // Wait a bit between increments.
runtime.Gosched() time.Sleep(time.Millisecond)
} }
}() }()
} }

View File

@ -1,2 +1,2 @@
ddfef8425eef64cfcb82799c9bddca4bfa9bbd29 ce8821f1f4fd99d554ad6cde52403dd3b69bb70a
2h8nvrnaHP 8p48eFFxDZ

View File

@ -1,7 +1,7 @@
# Running the program shows that we executed about # Running the program shows that we executed about
# 40,000 operations. # 40,000 operations.
$ go run atomic-counters.go $ go run atomic-counters.go
ops: 40200 ops: 41419
# Next we'll look at mutexes, another tool for managing # Next we'll look at mutexes, another tool for managing
# state. # state.

View File

@ -8,7 +8,6 @@ package main
import ( import (
"fmt" "fmt"
"math/rand" "math/rand"
"runtime"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -22,13 +21,14 @@ func main() {
// This `mutex` will synchronize access to `state`. // This `mutex` will synchronize access to `state`.
var mutex = &sync.Mutex{} var mutex = &sync.Mutex{}
// To compare the mutex-based approach with another // We'll keep track of how many read and write
// we'll see later, `ops` will count how many // operations we do.
// operations we perform against the state. var readOps uint64 = 0
var ops int64 = 0 var writeOps uint64 = 0
// Here we start 100 goroutines to execute repeated // Here we start 100 goroutines to execute repeated
// reads against the state. // reads against the state, once per millisecond in
// each goroutine.
for r := 0; r < 100; r++ { for r := 0; r < 100; r++ {
go func() { go func() {
total := 0 total := 0
@ -39,22 +39,15 @@ func main() {
// exclusive access to the `state`, read // exclusive access to the `state`, read
// the value at the chosen key, // the value at the chosen key,
// `Unlock()` the mutex, and increment // `Unlock()` the mutex, and increment
// the `ops` count. // the `readOps` count.
key := rand.Intn(5) key := rand.Intn(5)
mutex.Lock() mutex.Lock()
total += state[key] total += state[key]
mutex.Unlock() mutex.Unlock()
atomic.AddInt64(&ops, 1) atomic.AddUint64(&readOps, 1)
// In order to ensure that this goroutine // Wait a bit between reads.
// doesn't starve the scheduler, we explicitly time.Sleep(time.Millisecond)
// yield after each operation with
// `runtime.Gosched()`. This yielding is
// handled automatically with e.g. every
// channel operation and for blocking
// calls like `time.Sleep`, but in this
// case we need to do it manually.
runtime.Gosched()
} }
}() }()
} }
@ -69,8 +62,8 @@ func main() {
mutex.Lock() mutex.Lock()
state[key] = val state[key] = val
mutex.Unlock() mutex.Unlock()
atomic.AddInt64(&ops, 1) atomic.AddUint64(&writeOps, 1)
runtime.Gosched() time.Sleep(time.Millisecond)
} }
}() }()
} }
@ -79,9 +72,11 @@ func main() {
// `mutex` for a second. // `mutex` for a second.
time.Sleep(time.Second) time.Sleep(time.Second)
// Take and report a final operations count. // Take and report final operation counts.
opsFinal := atomic.LoadInt64(&ops) readOpsFinal := atomic.LoadUint64(&readOps)
fmt.Println("ops:", opsFinal) fmt.Println("readOps:", readOpsFinal)
writeOpsFinal := atomic.LoadUint64(&writeOps)
fmt.Println("writeOps:", writeOpsFinal)
// With a final lock of `state`, show how it ended up. // With a final lock of `state`, show how it ended up.
mutex.Lock() mutex.Lock()

View File

@ -1,2 +1,2 @@
3ce8467418aa740ea6c930afac3985a943c76311 e82356cbb37143862b0a9bbc68856f4b272c4918
kZrod-Rkos a9Wky7k-Bw

View File

@ -1,9 +1,10 @@
# Running the program shows that we executed about # Running the program shows that we executed about
# 3,500,000 operations against our `mutex`-synchronized # 90,000 total operations against our `mutex`-synchronized
# `state`. # `state`.
$ go run mutexes.go $ go run mutexes.go
ops: 3598302 readOps: 83285
state: map[1:38 4:98 2:23 3:85 0:44] writeOps: 8320
state: map[1:97 4:53 0:33 2:15 3:2]
# Next we'll look at implementing this same state # Next we'll look at implementing this same state
# management task using only goroutines and channels. # management task using only goroutines and channels.

View File

@ -37,7 +37,8 @@ type writeOp struct {
func main() { func main() {
// As before we'll count how many operations we perform. // As before we'll count how many operations we perform.
var ops int64 = 0 var readOps uint64 = 0
var writeOps uint64 = 0
// The `reads` and `writes` channels will be used by // The `reads` and `writes` channels will be used by
// other goroutines to issue read and write requests, // other goroutines to issue read and write requests,
@ -80,7 +81,8 @@ func main() {
resp: make(chan int)} resp: make(chan int)}
reads <- read reads <- read
<-read.resp <-read.resp
atomic.AddInt64(&ops, 1) atomic.AddUint64(&readOps, 1)
time.Sleep(time.Millisecond)
} }
}() }()
} }
@ -96,7 +98,8 @@ func main() {
resp: make(chan bool)} resp: make(chan bool)}
writes <- write writes <- write
<-write.resp <-write.resp
atomic.AddInt64(&ops, 1) atomic.AddUint64(&writeOps, 1)
time.Sleep(time.Millisecond)
} }
}() }()
} }
@ -104,7 +107,9 @@ func main() {
// Let the goroutines work for a second. // Let the goroutines work for a second.
time.Sleep(time.Second) time.Sleep(time.Second)
// Finally, capture and report the `ops` count. // Finally, capture and report the op counts.
opsFinal := atomic.LoadInt64(&ops) readOpsFinal := atomic.LoadUint64(&readOps)
fmt.Println("ops:", opsFinal) fmt.Println("readOps:", readOpsFinal)
writeOpsFinal := atomic.LoadUint64(&writeOps)
fmt.Println("writeOps:", writeOpsFinal)
} }

View File

@ -1,2 +1,2 @@
603a70a77ed18db9da4f8c7911a92b87fd21400c c306add52c0752f0b3099eb669364fc4bdb74be1
-WqmiTr6ek P4SrrlosMp

View File

@ -1,8 +1,9 @@
# Running our program shows that the goroutine-based # Running our program shows that the goroutine-based
# state management example achieves about 800,000 # state management example completes about 80,000
# operations per second. # total operations.
$ go run stateful-goroutines.go $ go run stateful-goroutines.go
ops: 807434 readOps: 71708
writeOps: 7177
# For this particular case the goroutine-based approach # For this particular case the goroutine-based approach
# was a bit more involved than the mutex-based one. It # was a bit more involved than the mutex-based one. It

View File

@ -44,7 +44,7 @@ counters</em> accessed by multiple goroutines.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
<a href="http://play.golang.org/p/2h8nvrnaHP"><img title="Run code" src="play.png" class="run" /></a> <a href="http://play.golang.org/p/8p48eFFxDZ"><img title="Run code" src="play.png" class="run" /></a>
<div class="highlight"><pre><span class="kn">package</span> <span class="nx">main</span> <div class="highlight"><pre><span class="kn">package</span> <span class="nx">main</span>
</pre></div> </pre></div>
@ -60,7 +60,6 @@ counters</em> accessed by multiple goroutines.</p>
<div class="highlight"><pre><span class="kn">import</span> <span class="s">&quot;fmt&quot;</span> <div class="highlight"><pre><span class="kn">import</span> <span class="s">&quot;fmt&quot;</span>
<span class="kn">import</span> <span class="s">&quot;time&quot;</span> <span class="kn">import</span> <span class="s">&quot;time&quot;</span>
<span class="kn">import</span> <span class="s">&quot;sync/atomic&quot;</span> <span class="kn">import</span> <span class="s">&quot;sync/atomic&quot;</span>
<span class="kn">import</span> <span class="s">&quot;runtime&quot;</span>
</pre></div> </pre></div>
</td> </td>
@ -127,12 +126,12 @@ address of our <code>ops</code> counter with the
<tr> <tr>
<td class="docs"> <td class="docs">
<p>Allow other goroutines to proceed.</p> <p>Wait a bit between increments.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
<div class="highlight"><pre> <span class="nx">runtime</span><span class="p">.</span><span class="nx">Gosched</span><span class="p">()</span> <div class="highlight"><pre> <span class="nx">time</span><span class="p">.</span><span class="nx">Sleep</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Millisecond</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
<span class="p">}()</span> <span class="p">}()</span>
<span class="p">}</span> <span class="p">}</span>
@ -187,7 +186,7 @@ fetch the value.</p>
<td class="code leading"> <td class="code leading">
<div class="highlight"><pre><span class="gp">$</span> go run atomic-counters.go <div class="highlight"><pre><span class="gp">$</span> go run atomic-counters.go
<span class="go">ops: 40200</span> <span class="go">ops: 41419</span>
</pre></div> </pre></div>
</td> </td>

View File

@ -42,7 +42,7 @@ to safely access data across multiple goroutines.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
<a href="http://play.golang.org/p/kZrod-Rkos"><img title="Run code" src="play.png" class="run" /></a> <a href="http://play.golang.org/p/a9Wky7k-Bw"><img title="Run code" src="play.png" class="run" /></a>
<div class="highlight"><pre><span class="kn">package</span> <span class="nx">main</span> <div class="highlight"><pre><span class="kn">package</span> <span class="nx">main</span>
</pre></div> </pre></div>
@ -58,7 +58,6 @@ to safely access data across multiple goroutines.</p>
<div class="highlight"><pre><span class="kn">import</span> <span class="p">(</span> <div class="highlight"><pre><span class="kn">import</span> <span class="p">(</span>
<span class="s">&quot;fmt&quot;</span> <span class="s">&quot;fmt&quot;</span>
<span class="s">&quot;math/rand&quot;</span> <span class="s">&quot;math/rand&quot;</span>
<span class="s">&quot;runtime&quot;</span>
<span class="s">&quot;sync&quot;</span> <span class="s">&quot;sync&quot;</span>
<span class="s">&quot;sync/atomic&quot;</span> <span class="s">&quot;sync/atomic&quot;</span>
<span class="s">&quot;time&quot;</span> <span class="s">&quot;time&quot;</span>
@ -108,14 +107,14 @@ to safely access data across multiple goroutines.</p>
<tr> <tr>
<td class="docs"> <td class="docs">
<p>To compare the mutex-based approach with another <p>We&rsquo;ll keep track of how many read and write
we&rsquo;ll see later, <code>ops</code> will count how many operations we do.</p>
operations we perform against the state.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
<div class="highlight"><pre> <span class="kd">var</span> <span class="nx">ops</span> <span class="kt">int64</span> <span class="p">=</span> <span class="mi">0</span> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">readOps</span> <span class="kt">uint64</span> <span class="p">=</span> <span class="mi">0</span>
<span class="kd">var</span> <span class="nx">writeOps</span> <span class="kt">uint64</span> <span class="p">=</span> <span class="mi">0</span>
</pre></div> </pre></div>
</td> </td>
@ -124,7 +123,8 @@ operations we perform against the state.</p>
<tr> <tr>
<td class="docs"> <td class="docs">
<p>Here we start 100 goroutines to execute repeated <p>Here we start 100 goroutines to execute repeated
reads against the state.</p> reads against the state, once per millisecond in
each goroutine.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
@ -145,7 +145,7 @@ reads against the state.</p>
exclusive access to the <code>state</code>, read exclusive access to the <code>state</code>, read
the value at the chosen key, the value at the chosen key,
<code>Unlock()</code> the mutex, and increment <code>Unlock()</code> the mutex, and increment
the <code>ops</code> count.</p> the <code>readOps</code> count.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
@ -154,7 +154,7 @@ the <code>ops</code> count.</p>
<span class="nx">mutex</span><span class="p">.</span><span class="nx">Lock</span><span class="p">()</span> <span class="nx">mutex</span><span class="p">.</span><span class="nx">Lock</span><span class="p">()</span>
<span class="nx">total</span> <span class="o">+=</span> <span class="nx">state</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="nx">total</span> <span class="o">+=</span> <span class="nx">state</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span>
<span class="nx">mutex</span><span class="p">.</span><span class="nx">Unlock</span><span class="p">()</span> <span class="nx">mutex</span><span class="p">.</span><span class="nx">Unlock</span><span class="p">()</span>
<span class="nx">atomic</span><span class="p">.</span><span class="nx">AddInt64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ops</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">AddUint64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">readOps</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</pre></div> </pre></div>
</td> </td>
@ -162,19 +162,12 @@ the <code>ops</code> count.</p>
<tr> <tr>
<td class="docs"> <td class="docs">
<p>In order to ensure that this goroutine <p>Wait a bit between reads.</p>
doesn&rsquo;t starve the scheduler, we explicitly
yield after each operation with
<code>runtime.Gosched()</code>. This yielding is
handled automatically with e.g. every
channel operation and for blocking
calls like <code>time.Sleep</code>, but in this
case we need to do it manually.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
<div class="highlight"><pre> <span class="nx">runtime</span><span class="p">.</span><span class="nx">Gosched</span><span class="p">()</span> <div class="highlight"><pre> <span class="nx">time</span><span class="p">.</span><span class="nx">Sleep</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Millisecond</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
<span class="p">}()</span> <span class="p">}()</span>
<span class="p">}</span> <span class="p">}</span>
@ -199,8 +192,8 @@ using the same pattern we did for reads.</p>
<span class="nx">mutex</span><span class="p">.</span><span class="nx">Lock</span><span class="p">()</span> <span class="nx">mutex</span><span class="p">.</span><span class="nx">Lock</span><span class="p">()</span>
<span class="nx">state</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="p">=</span> <span class="nx">val</span> <span class="nx">state</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="p">=</span> <span class="nx">val</span>
<span class="nx">mutex</span><span class="p">.</span><span class="nx">Unlock</span><span class="p">()</span> <span class="nx">mutex</span><span class="p">.</span><span class="nx">Unlock</span><span class="p">()</span>
<span class="nx">atomic</span><span class="p">.</span><span class="nx">AddInt64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ops</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">AddUint64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">writeOps</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="nx">runtime</span><span class="p">.</span><span class="nx">Gosched</span><span class="p">()</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Sleep</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Millisecond</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
<span class="p">}()</span> <span class="p">}()</span>
<span class="p">}</span> <span class="p">}</span>
@ -225,13 +218,15 @@ using the same pattern we did for reads.</p>
<tr> <tr>
<td class="docs"> <td class="docs">
<p>Take and report a final operations count.</p> <p>Take and report final operation counts.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
<div class="highlight"><pre> <span class="nx">opsFinal</span> <span class="o">:=</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">LoadInt64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ops</span><span class="p">)</span> <div class="highlight"><pre> <span class="nx">readOpsFinal</span> <span class="o">:=</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">LoadUint64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">readOps</span><span class="p">)</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;ops:&quot;</span><span class="p">,</span> <span class="nx">opsFinal</span><span class="p">)</span> <span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;readOps:&quot;</span><span class="p">,</span> <span class="nx">readOpsFinal</span><span class="p">)</span>
<span class="nx">writeOpsFinal</span> <span class="o">:=</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">LoadUint64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">writeOps</span><span class="p">)</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;writeOps:&quot;</span><span class="p">,</span> <span class="nx">writeOpsFinal</span><span class="p">)</span>
</pre></div> </pre></div>
</td> </td>
@ -260,15 +255,16 @@ using the same pattern we did for reads.</p>
<tr> <tr>
<td class="docs"> <td class="docs">
<p>Running the program shows that we executed about <p>Running the program shows that we executed about
3,500,000 operations against our <code>mutex</code>-synchronized 90,000 total operations against our <code>mutex</code>-synchronized
<code>state</code>.</p> <code>state</code>.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
<div class="highlight"><pre><span class="gp">$</span> go run mutexes.go <div class="highlight"><pre><span class="gp">$</span> go run mutexes.go
<span class="go">ops: 3598302</span> <span class="go">readOps: 83285</span>
<span class="go">state: map[1:38 4:98 2:23 3:85 0:44]</span> <span class="go">writeOps: 8320</span>
<span class="go">state: map[1:97 4:53 0:33 2:15 3:2]</span>
</pre></div> </pre></div>
</td> </td>

View File

@ -46,7 +46,7 @@ by exactly 1 goroutine.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
<a href="http://play.golang.org/p/-WqmiTr6ek"><img title="Run code" src="play.png" class="run" /></a> <a href="http://play.golang.org/p/P4SrrlosMp"><img title="Run code" src="play.png" class="run" /></a>
<div class="highlight"><pre><span class="kn">package</span> <span class="nx">main</span> <div class="highlight"><pre><span class="kn">package</span> <span class="nx">main</span>
</pre></div> </pre></div>
@ -117,7 +117,8 @@ goroutine to respond.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
<div class="highlight"><pre> <span class="kd">var</span> <span class="nx">ops</span> <span class="kt">int64</span> <span class="p">=</span> <span class="mi">0</span> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">readOps</span> <span class="kt">uint64</span> <span class="p">=</span> <span class="mi">0</span>
<span class="kd">var</span> <span class="nx">writeOps</span> <span class="kt">uint64</span> <span class="p">=</span> <span class="mi">0</span>
</pre></div> </pre></div>
</td> </td>
@ -190,7 +191,8 @@ result over the provided <code>resp</code> channel.</p>
<span class="nx">resp</span><span class="p">:</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int</span><span class="p">)}</span> <span class="nx">resp</span><span class="p">:</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int</span><span class="p">)}</span>
<span class="nx">reads</span> <span class="o">&lt;-</span> <span class="nx">read</span> <span class="nx">reads</span> <span class="o">&lt;-</span> <span class="nx">read</span>
<span class="o">&lt;-</span><span class="nx">read</span><span class="p">.</span><span class="nx">resp</span> <span class="o">&lt;-</span><span class="nx">read</span><span class="p">.</span><span class="nx">resp</span>
<span class="nx">atomic</span><span class="p">.</span><span class="nx">AddInt64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ops</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">AddUint64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">readOps</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="nx">time</span><span class="p">.</span><span class="nx">Sleep</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Millisecond</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
<span class="p">}()</span> <span class="p">}()</span>
<span class="p">}</span> <span class="p">}</span>
@ -216,7 +218,8 @@ approach.</p>
<span class="nx">resp</span><span class="p">:</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">bool</span><span class="p">)}</span> <span class="nx">resp</span><span class="p">:</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">bool</span><span class="p">)}</span>
<span class="nx">writes</span> <span class="o">&lt;-</span> <span class="nx">write</span> <span class="nx">writes</span> <span class="o">&lt;-</span> <span class="nx">write</span>
<span class="o">&lt;-</span><span class="nx">write</span><span class="p">.</span><span class="nx">resp</span> <span class="o">&lt;-</span><span class="nx">write</span><span class="p">.</span><span class="nx">resp</span>
<span class="nx">atomic</span><span class="p">.</span><span class="nx">AddInt64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ops</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">AddUint64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">writeOps</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="nx">time</span><span class="p">.</span><span class="nx">Sleep</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Millisecond</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
<span class="p">}()</span> <span class="p">}()</span>
<span class="p">}</span> <span class="p">}</span>
@ -240,13 +243,15 @@ approach.</p>
<tr> <tr>
<td class="docs"> <td class="docs">
<p>Finally, capture and report the <code>ops</code> count.</p> <p>Finally, capture and report the op counts.</p>
</td> </td>
<td class="code"> <td class="code">
<div class="highlight"><pre> <span class="nx">opsFinal</span> <span class="o">:=</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">LoadInt64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ops</span><span class="p">)</span> <div class="highlight"><pre> <span class="nx">readOpsFinal</span> <span class="o">:=</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">LoadUint64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">readOps</span><span class="p">)</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;ops:&quot;</span><span class="p">,</span> <span class="nx">opsFinal</span><span class="p">)</span> <span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;readOps:&quot;</span><span class="p">,</span> <span class="nx">readOpsFinal</span><span class="p">)</span>
<span class="nx">writeOpsFinal</span> <span class="o">:=</span> <span class="nx">atomic</span><span class="p">.</span><span class="nx">LoadUint64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">writeOps</span><span class="p">)</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;writeOps:&quot;</span><span class="p">,</span> <span class="nx">writeOpsFinal</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
</pre></div> </pre></div>
@ -260,14 +265,15 @@ approach.</p>
<tr> <tr>
<td class="docs"> <td class="docs">
<p>Running our program shows that the goroutine-based <p>Running our program shows that the goroutine-based
state management example achieves about 800,000 state management example completes about 80,000
operations per second.</p> total operations.</p>
</td> </td>
<td class="code leading"> <td class="code leading">
<div class="highlight"><pre><span class="gp">$</span> go run stateful-goroutines.go <div class="highlight"><pre><span class="gp">$</span> go run stateful-goroutines.go
<span class="go">ops: 807434</span> <span class="go">readOps: 71708</span>
<span class="go">writeOps: 7177</span>
</pre></div> </pre></div>
</td> </td>