Change mutexes example to make it simpler and more predictable
Fixes #364
This commit is contained in:
parent
e10011f90f
commit
f09cadcbd9
@ -7,79 +7,57 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// For our example the `state` will be a map.
|
||||
var state = make(map[int]int)
|
||||
|
||||
// This `mutex` will synchronize access to `state`.
|
||||
var mutex = &sync.Mutex{}
|
||||
|
||||
// We'll keep track of how many read and write
|
||||
// operations we do.
|
||||
var readOps uint64
|
||||
var writeOps uint64
|
||||
|
||||
// Here we start 100 goroutines to execute repeated
|
||||
// reads against the state, once per millisecond in
|
||||
// each goroutine.
|
||||
for r := 0; r < 100; r++ {
|
||||
go func() {
|
||||
total := 0
|
||||
for {
|
||||
|
||||
// For each read we pick a key to access,
|
||||
// `Lock()` the `mutex` to ensure
|
||||
// exclusive access to the `state`, read
|
||||
// the value at the chosen key,
|
||||
// `Unlock()` the mutex, and increment
|
||||
// the `readOps` count.
|
||||
key := rand.Intn(5)
|
||||
mutex.Lock()
|
||||
total += state[key]
|
||||
mutex.Unlock()
|
||||
atomic.AddUint64(&readOps, 1)
|
||||
|
||||
// Wait a bit between reads.
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// We'll also start 10 goroutines to simulate writes,
|
||||
// using the same pattern we did for reads.
|
||||
for w := 0; w < 10; w++ {
|
||||
go func() {
|
||||
for {
|
||||
key := rand.Intn(5)
|
||||
val := rand.Intn(100)
|
||||
mutex.Lock()
|
||||
state[key] = val
|
||||
mutex.Unlock()
|
||||
atomic.AddUint64(&writeOps, 1)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Let the 10 goroutines work on the `state` and
|
||||
// `mutex` for a second.
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// Take and report final operation counts.
|
||||
readOpsFinal := atomic.LoadUint64(&readOps)
|
||||
fmt.Println("readOps:", readOpsFinal)
|
||||
writeOpsFinal := atomic.LoadUint64(&writeOps)
|
||||
fmt.Println("writeOps:", writeOpsFinal)
|
||||
|
||||
// With a final lock of `state`, show how it ended up.
|
||||
mutex.Lock()
|
||||
fmt.Println("state:", state)
|
||||
mutex.Unlock()
|
||||
// Container holds a map of counters; since we want to
|
||||
// update it concurrently from multiple goroutines, we
|
||||
// add a `Mutex` to synchronize access. The mutex is
|
||||
// _embedded_ in this `struct`; this is idiomatic in Go.
|
||||
// Note that mutexes must not be copied, so if this
|
||||
// `struct` is passed around, it should be done by
|
||||
// pointer.
|
||||
type Container struct {
|
||||
sync.Mutex
|
||||
counters map[string]int
|
||||
}
|
||||
|
||||
func (c *Container) inc(name string) {
|
||||
// Lock the mutex before accessing `counters`; unlock
|
||||
// it at the end of the function using a [defer](defer)
|
||||
// statement. Since the mutex is embedded into
|
||||
// `Container`, we can call the mutex's methods like
|
||||
// `Lock` directly on `c`.
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
c.counters[name]++
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := Container{
|
||||
counters: map[string]int{"a": 0, "b": 0},
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// This function increments a named counter
|
||||
// in a loop.
|
||||
doIncrement := func(name string, n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
c.inc(name)
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
// Run several goroutines concurrently; note
|
||||
// that they all access the same `Container`,
|
||||
// and two of them access the same counter.
|
||||
wg.Add(3)
|
||||
go doIncrement("a", 10000)
|
||||
go doIncrement("a", 10000)
|
||||
go doIncrement("b", 10000)
|
||||
|
||||
// Wait a for the goroutines to finish
|
||||
wg.Wait()
|
||||
fmt.Println(c.counters)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
253b089b8145fc57a90ae4024346b6db2ec1659b
|
||||
CHCDredHCOz
|
||||
07179e54fb3466ab01ac8aa9550feb213a206785
|
||||
i50fhu4l-n0
|
||||
|
@ -1,10 +1,7 @@
|
||||
# Running the program shows that we executed about
|
||||
# 90,000 total operations against our `mutex`-synchronized
|
||||
# `state`.
|
||||
# Running the program shows that the counters
|
||||
# updated as expected.
|
||||
$ go run mutexes.go
|
||||
readOps: 83285
|
||||
writeOps: 8320
|
||||
state: map[1:97 4:53 0:33 2:15 3:2]
|
||||
map[a:20000 b:10000]
|
||||
|
||||
# Next we'll look at implementing this same state
|
||||
# management task using only goroutines and channels.
|
||||
|
229
public/mutexes
generated
229
public/mutexes
generated
@ -44,7 +44,7 @@ to safely access data across multiple goroutines.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
<a href="http://play.golang.org/p/CHCDredHCOz"><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/i50fhu4l-n0"><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>
|
||||
@ -58,15 +58,64 @@ to safely access data across multiple goroutines.</p>
|
||||
|
||||
<pre class="chroma"><span class="kn">import</span> <span class="p">(</span>
|
||||
<span class="s">"fmt"</span>
|
||||
<span class="s">"math/rand"</span>
|
||||
<span class="s">"sync"</span>
|
||||
<span class="s">"sync/atomic"</span>
|
||||
<span class="s">"time"</span>
|
||||
<span class="p">)</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>Container holds a map of counters; since we want to
|
||||
update it concurrently from multiple goroutines, we
|
||||
add a <code>Mutex</code> to synchronize access. The mutex is
|
||||
<em>embedded</em> in this <code>struct</code>; this is idiomatic in Go.
|
||||
Note that mutexes must not be copied, so if this
|
||||
<code>struct</code> is passed around, it should be done by
|
||||
pointer.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="kd">type</span> <span class="nx">Container</span> <span class="kd">struct</span> <span class="p">{</span>
|
||||
<span class="nx">sync</span><span class="p">.</span><span class="nx">Mutex</span>
|
||||
<span class="nx">counters</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span>
|
||||
<span class="p">}</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>Lock the mutex before accessing <code>counters</code>; unlock
|
||||
it at the end of the function using a <a href="defer">defer</a>
|
||||
statement. Since the mutex is embedded into
|
||||
<code>Container</code>, we can call the mutex’s methods like
|
||||
<code>Lock</code> directly on <code>c</code>.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma"><span class="kd">func</span> <span class="p">(</span><span class="nx">c</span> <span class="o">*</span><span class="nx">Container</span><span class="p">)</span> <span class="nf">inc</span><span class="p">(</span><span class="nx">name</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma"> <span class="nx">c</span><span class="p">.</span><span class="nf">Lock</span><span class="p">()</span>
|
||||
<span class="k">defer</span> <span class="nx">c</span><span class="p">.</span><span class="nf">Unlock</span><span class="p">()</span>
|
||||
<span class="nx">c</span><span class="p">.</span><span class="nx">counters</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">++</span>
|
||||
<span class="p">}</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
|
||||
@ -74,102 +123,8 @@ to safely access data across multiple goroutines.</p>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>For our example the <code>state</code> will be a map.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="kd">var</span> <span class="nx">state</span> <span class="p">=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">int</span><span class="p">]</span><span class="kt">int</span><span class="p">)</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>This <code>mutex</code> will synchronize access to <code>state</code>.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="kd">var</span> <span class="nx">mutex</span> <span class="p">=</span> <span class="o">&</span><span class="nx">sync</span><span class="p">.</span><span class="nx">Mutex</span><span class="p">{}</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>We’ll keep track of how many read and write
|
||||
operations we do.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="kd">var</span> <span class="nx">readOps</span> <span class="kt">uint64</span>
|
||||
<span class="kd">var</span> <span class="nx">writeOps</span> <span class="kt">uint64</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>Here we start 100 goroutines to execute repeated
|
||||
reads against the state, once per millisecond in
|
||||
each goroutine.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="k">for</span> <span class="nx">r</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">r</span> <span class="p"><</span> <span class="mi">100</span><span class="p">;</span> <span class="nx">r</span><span class="o">++</span> <span class="p">{</span>
|
||||
<span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
|
||||
<span class="nx">total</span> <span class="o">:=</span> <span class="mi">0</span>
|
||||
<span class="k">for</span> <span class="p">{</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>For each read we pick a key to access,
|
||||
<code>Lock()</code> the <code>mutex</code> to ensure
|
||||
exclusive access to the <code>state</code>, read
|
||||
the value at the chosen key,
|
||||
<code>Unlock()</code> the mutex, and increment
|
||||
the <code>readOps</code> count.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="nx">key</span> <span class="o">:=</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">Intn</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
||||
<span class="nx">mutex</span><span class="p">.</span><span class="nf">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">mutex</span><span class="p">.</span><span class="nf">Unlock</span><span class="p">()</span>
|
||||
<span class="nx">atomic</span><span class="p">.</span><span class="nf">AddUint64</span><span class="p">(</span><span class="o">&</span><span class="nx">readOps</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>Wait a bit between reads.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="nx">time</span><span class="p">.</span><span class="nf">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="nx">c</span> <span class="o">:=</span> <span class="nx">Container</span><span class="p">{</span>
|
||||
<span class="nx">counters</span><span class="p">:</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="s">"a"</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"b"</span><span class="p">:</span> <span class="mi">0</span><span class="p">},</span>
|
||||
<span class="p">}</span>
|
||||
</pre>
|
||||
</td>
|
||||
@ -177,25 +132,29 @@ the <code>readOps</code> count.</p>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>We’ll also start 10 goroutines to simulate writes,
|
||||
using the same pattern we did for reads.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma"> <span class="kd">var</span> <span class="nx">wg</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>This function increments a named counter
|
||||
in a loop.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="k">for</span> <span class="nx">w</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">w</span> <span class="p"><</span> <span class="mi">10</span><span class="p">;</span> <span class="nx">w</span><span class="o">++</span> <span class="p">{</span>
|
||||
<span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
|
||||
<span class="k">for</span> <span class="p">{</span>
|
||||
<span class="nx">key</span> <span class="o">:=</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">Intn</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
||||
<span class="nx">val</span> <span class="o">:=</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">Intn</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
|
||||
<span class="nx">mutex</span><span class="p">.</span><span class="nf">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">mutex</span><span class="p">.</span><span class="nf">Unlock</span><span class="p">()</span>
|
||||
<span class="nx">atomic</span><span class="p">.</span><span class="nf">AddUint64</span><span class="p">(</span><span class="o">&</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="nf">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="nx">doIncrement</span> <span class="o">:=</span> <span class="kd">func</span><span class="p">(</span><span class="nx">name</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
|
||||
<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="nx">n</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
|
||||
<span class="nx">c</span><span class="p">.</span><span class="nf">inc</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}()</span>
|
||||
<span class="nx">wg</span><span class="p">.</span><span class="nf">Done</span><span class="p">()</span>
|
||||
<span class="p">}</span>
|
||||
</pre>
|
||||
</td>
|
||||
@ -203,45 +162,32 @@ using the same pattern we did for reads.</p>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>Let the 10 goroutines work on the <code>state</code> and
|
||||
<code>mutex</code> for a second.</p>
|
||||
<p>Run several goroutines concurrently; note
|
||||
that they all access the same <code>Container</code>,
|
||||
and two of them access the same counter.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="nx">time</span><span class="p">.</span><span class="nf">Sleep</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</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">3</span><span class="p">)</span>
|
||||
<span class="k">go</span> <span class="nf">doIncrement</span><span class="p">(</span><span class="s">"a"</span><span class="p">,</span> <span class="mi">10000</span><span class="p">)</span>
|
||||
<span class="k">go</span> <span class="nf">doIncrement</span><span class="p">(</span><span class="s">"a"</span><span class="p">,</span> <span class="mi">10000</span><span class="p">)</span>
|
||||
<span class="k">go</span> <span class="nf">doIncrement</span><span class="p">(</span><span class="s">"b"</span><span class="p">,</span> <span class="mi">10000</span><span class="p">)</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>Take and report final operation counts.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="nx">readOpsFinal</span> <span class="o">:=</span> <span class="nx">atomic</span><span class="p">.</span><span class="nf">LoadUint64</span><span class="p">(</span><span class="o">&</span><span class="nx">readOps</span><span class="p">)</span>
|
||||
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"readOps:"</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="nf">LoadUint64</span><span class="p">(</span><span class="o">&</span><span class="nx">writeOps</span><span class="p">)</span>
|
||||
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"writeOps:"</span><span class="p">,</span> <span class="nx">writeOpsFinal</span><span class="p">)</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>With a final lock of <code>state</code>, show how it ended up.</p>
|
||||
<p>Wait a for the goroutines to finish</p>
|
||||
|
||||
</td>
|
||||
<td class="code">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="nx">mutex</span><span class="p">.</span><span class="nf">Lock</span><span class="p">()</span>
|
||||
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"state:"</span><span class="p">,</span> <span class="nx">state</span><span class="p">)</span>
|
||||
<span class="nx">mutex</span><span class="p">.</span><span class="nf">Unlock</span><span class="p">()</span>
|
||||
<span class="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span>
|
||||
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">counters</span><span class="p">)</span>
|
||||
<span class="p">}</span>
|
||||
</pre>
|
||||
</td>
|
||||
@ -253,18 +199,15 @@ using the same pattern we did for reads.</p>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>Running the program shows that we executed about
|
||||
90,000 total operations against our <code>mutex</code>-synchronized
|
||||
<code>state</code>.</p>
|
||||
<p>Running the program shows that the counters
|
||||
updated as expected.</p>
|
||||
|
||||
</td>
|
||||
<td class="code leading">
|
||||
|
||||
<pre class="chroma">
|
||||
<span class="gp">$</span> go run mutexes.go
|
||||
<span class="go">readOps: 83285
|
||||
</span><span class="go">writeOps: 8320
|
||||
</span><span class="go">state: map[1:97 4:53 0:33 2:15 3:2]</span></pre>
|
||||
<span class="go">map[a:20000 b:10000]</span></pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -295,7 +238,7 @@ management task using only goroutines and channels.</p>
|
||||
</div>
|
||||
<script>
|
||||
var codeLines = [];
|
||||
codeLines.push('');codeLines.push('package main\u000A');codeLines.push('import (\u000A \"fmt\"\u000A \"math/rand\"\u000A \"sync\"\u000A \"sync/atomic\"\u000A \"time\"\u000A)\u000A');codeLines.push('func main() {\u000A');codeLines.push(' var state \u003D make(map[int]int)\u000A');codeLines.push(' var mutex \u003D \u0026sync.Mutex{}\u000A');codeLines.push(' var readOps uint64\u000A var writeOps uint64\u000A');codeLines.push(' for r :\u003D 0; r \u003C 100; r++ {\u000A go func() {\u000A total :\u003D 0\u000A for {\u000A');codeLines.push(' key :\u003D rand.Intn(5)\u000A mutex.Lock()\u000A total +\u003D state[key]\u000A mutex.Unlock()\u000A atomic.AddUint64(\u0026readOps, 1)\u000A');codeLines.push(' time.Sleep(time.Millisecond)\u000A }\u000A }()\u000A }\u000A');codeLines.push(' for w :\u003D 0; w \u003C 10; w++ {\u000A go func() {\u000A for {\u000A key :\u003D rand.Intn(5)\u000A val :\u003D rand.Intn(100)\u000A mutex.Lock()\u000A state[key] \u003D val\u000A mutex.Unlock()\u000A atomic.AddUint64(\u0026writeOps, 1)\u000A time.Sleep(time.Millisecond)\u000A }\u000A }()\u000A }\u000A');codeLines.push(' time.Sleep(time.Second)\u000A');codeLines.push(' readOpsFinal :\u003D atomic.LoadUint64(\u0026readOps)\u000A fmt.Println(\"readOps:\", readOpsFinal)\u000A writeOpsFinal :\u003D atomic.LoadUint64(\u0026writeOps)\u000A fmt.Println(\"writeOps:\", writeOpsFinal)\u000A');codeLines.push(' mutex.Lock()\u000A fmt.Println(\"state:\", state)\u000A mutex.Unlock()\u000A}\u000A');codeLines.push('');codeLines.push('');
|
||||
codeLines.push('');codeLines.push('package main\u000A');codeLines.push('import (\u000A \"fmt\"\u000A \"sync\"\u000A)\u000A');codeLines.push('type Container struct {\u000A sync.Mutex\u000A counters map[string]int\u000A}\u000A');codeLines.push('func (c *Container) inc(name string) {\u000A');codeLines.push(' c.Lock()\u000A defer c.Unlock()\u000A c.counters[name]++\u000A}\u000A');codeLines.push('func main() {\u000A c :\u003D Container{\u000A counters: map[string]int{\"a\": 0, \"b\": 0},\u000A }\u000A');codeLines.push(' var wg sync.WaitGroup\u000A');codeLines.push(' doIncrement :\u003D func(name string, n int) {\u000A for i :\u003D 0; i \u003C n; i++ {\u000A c.inc(name)\u000A }\u000A wg.Done()\u000A }\u000A');codeLines.push(' wg.Add(3)\u000A go doIncrement(\"a\", 10000)\u000A go doIncrement(\"a\", 10000)\u000A go doIncrement(\"b\", 10000)\u000A');codeLines.push(' wg.Wait()\u000A fmt.Println(c.counters)\u000A}\u000A');codeLines.push('');codeLines.push('');
|
||||
</script>
|
||||
<script src="site.js" async></script>
|
||||
</body>
|
||||
|
Loading…
x
Reference in New Issue
Block a user