List of Concurrency - text.Baldanders.info
tag:text.Baldanders.info,2023-06-26:/tags
2023-06-26T21:22:20+09:00
帰ってきた「しっぽのさきっちょ」
https://text.baldanders.info/images/avatar.jpg
https://text.baldanders.info/images/avatar.jpg
goark/errs パッケージ v1.3.2 をリリースした
tag:text.Baldanders.info,2023-06-26:/release/2023/06/errs-package-v1_3_2-is-released/
2023-06-26T12:22:20+00:00
2023-06-26T23:10:38+00:00
concurrency-safe なマルチエラー型を作った。
Spiegel
https://baldanders.info/profile/
<p><a href="https://text.baldanders.info/remark/2023/06/benchmark-for-errs-package/" title="拙作 gorak/errs パッケージの性能評価をしてもらった">この前書いた記事</a>で,最後の方に「そうそう <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.Join</code> 互換の関数ってあったほうがいいのかなぁ」と漠然と書いたのだが,その後,複数の goroutine を跨いでエラーハンドリングを行う必要ができたので, concurrency-safe なマルチエラー型 <a href="https://github.com/goark/errs" title="goark/errs: Error handling for Golang"><code>errs</code></a><code>.Errors</code> を作ってリリースした。</p>
<ul>
<li><a href="https://github.com/goark/errs/releases/tag/v1.3.2">Release v1.3.2 · goark/errs · GitHub</a></li>
</ul>
<p>いやぁ,並行処理書くの久しぶりで,色々とバグを潰してたら v1.3.2 まで上がってしまった(笑)</p>
<p>たとえば,こんな感じに使える。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><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></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/errs"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">generateMultiError</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">errlist</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">errs</span><span class="p">.</span><span class="nx">Errors</span><span class="p">{}</span>
</span></span><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><span class="line"><span class="cl"> <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">2</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">i</span> <span class="o">:=</span> <span class="nx">i</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><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">defer</span> <span class="nx">wg</span><span class="p">.</span><span class="nf">Done</span><span class="p">()</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">errlist</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"error %d"</span><span class="p">,</span> <span class="nx">i</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><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><span class="line hl"><span class="cl"> <span class="k">return</span> <span class="nx">errlist</span><span class="p">.</span><span class="nf">ErrorOrNil</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></span><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><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">generateMultiError</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%+v\n"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span> <span class="c1">// {"Type":"*errs.Errors","Errs":[{"Type":"*errors.errorString","Msg":"error 2"},{"Type":"*errors.errorString","Msg":"error 1"}]}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>また <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.Join()</code> 互換の関数も用意してみた。
こんな感じ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><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">"errors"</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">"io"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"os"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/errs"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">generateMultiError</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</span> <span class="nx">errs</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">ErrInvalid</span><span class="p">,</span> <span class="nx">io</span><span class="p">.</span><span class="nx">EOF</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></span><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><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">generateMultiError</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%+v\n"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span> <span class="c1">// {"Type":"*errs.Errors","Errs":[{"Type":"*errors.errorString","Msg":"invalid argument"},{"Type":"*errors.errorString","Msg":"EOF"}]}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">errors</span><span class="p">.</span><span class="nf">Is</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">io</span><span class="p">.</span><span class="nx">EOF</span><span class="p">))</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>今回新たに作った <a href="https://github.com/goark/errs" title="goark/errs: Error handling for Golang"><code>errs</code></a><code>.Errors</code> 型は <code>Unwrap() []error</code> メソッドを持っているため, <a href="https://go.dev/">Go</a> 1.20 以降であれば <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.Is()</code> および <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.As()</code> 関数を使って評価することができる。</p>
<p>これで <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a> 標準パッケージと互換性ありと言えるようになったかな?</p>
<h2>ブックマーク</h2>
<ul>
<li>
<p><a href="https://tech.kanmu.co.jp/entry/2023/06/19/150000">次なる<code>pkg/errors</code>を探して - カンムテックブログ</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/golang/wrapping-multiple-errors/">【Go 1.20 の予習】複数 error を返す Unwrap メソッドについて</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/release/errs-package-for-golang/">Go 言語用エラーハンドリング・パッケージ</a></p>
</li>
<li>
<p><a href="https://zenn.dev/spiegel/books/error-handling-in-golang">Go のエラーハンドリング</a> : Zenn 本書きました</p>
</li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51pUKQajnaL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語による並行処理</a></dt>
<dd>Katherine Cox-Buday (著), 山口 能迪 (翻訳)</dd>
<dd>オライリージャパン 2018-10-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118468 (ASIN), 9784873118468 (EAN), 4873118468 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118468/">Eブック版もある</a>。感想は<a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">こちら</a>。 Go 言語で並行処理を書くならこの本は必読書になるだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-01-13">2020-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語による並行処理 -->
Go による Token Bucket 実装
tag:text.Baldanders.info,2021-06-03:/golang/token-bucket/
2021-06-03T11:44:50+00:00
2021-12-04T02:40:05+00:00
golang.org/x/time/rate パッケージを使う。
Spiegel
https://baldanders.info/profile/
<p>Qiita で</p>
<ul>
<li><a href="https://qiita.com/msh5/items/f203f85452c5b814ba36">golang.org/x/time/rate でレイトリミット - Qiita</a></li>
</ul>
<p>という記事を見かける。</p>
<p><a href="https://pkg.go.dev/golang.org/x/time/rate" title="rate · pkg.go.dev"><code>golang.org/x/time/rate</code></a> は,いわゆる「トークンバケット(token bucket)」アルゴリズムを実装するためのパッケージのようだ。
トークンバケット・アルゴリズムとは</p>
<figure lang="en">
<blockquote><ul>
<li>A token is added to the bucket every $1/r$ seconds.</li>
<li>The bucket can hold at the most $b$ tokens. If a token arrives when the bucket is full, it is discarded.</li>
<li>When a packet (network layer PDU) of $n$ bytes arrives,
<ul>
<li>if at least $n$ tokens are in the bucket, $n$ tokens are removed from the bucket, and the packet is sent to the network.</li>
<li>if fewer than $n$ tokens are available, no tokens are removed from the bucket, and the packet is considered to be non-conformant.</li>
</ul>
</li>
</ul>
</blockquote>
<figcaption><div>via <q><a href="https://en.wikipedia.org/wiki/Token_bucket">Token bucket - Wikipedia</a></q></div></figcaption>
</figure>
<p>といったものらしい。
具体的には</p>
<figure lang="en">
<blockquote class="nobox"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">NewLimiter</span><span class="p">(</span><span class="nx">r</span> <span class="nx">Limit</span><span class="p">,</span> <span class="nx">b</span> <span class="kt">int</span><span class="p">)</span> <span class="o">*</span><span class="nx">Limiter</span>
</span></span></code></pre></div></blockquote>
<figcaption><div>via <q><a href="https://pkg.go.dev/golang.org/x/time/rate">rate · pkg.go.dev</a></q></div></figcaption>
</figure>
<p>で生成される <a href="https://pkg.go.dev/golang.org/x/time/rate" title="rate · pkg.go.dev"><code>rate</code></a><code>.Limiter</code> 型のインスタンスが上の説明の「バケット」に相当するようだ。
引数の <code>r</code> と <code>b</code> も同じ意味かな。</p>
<p>これを並行処理のジェネレータ・パターンと組み合わせると面白そうである。</p>
<p>というわけで,まずは以下のコードを起点としてみよう。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go:sample1.go" data-lang="go:sample1.go"><span class="line"><span class="cl"><span class="c1">// +build run
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><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="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">generater</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="nx">ch</span> <span class="kd">chan</span><span class="o"><-</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nb">close</span><span class="p">(</span><span class="nx">ch</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">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="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">10</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">ch</span> <span class="o"><-</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</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><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">output</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="nx">num</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">ch</span> <span class="o"><-</span><span class="kd">chan</span> <span class="kt">int</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">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">ch</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Worker %d: %v\n"</span><span class="p">,</span> <span class="nx">num</span><span class="p">,</span> <span class="nx">n</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="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></span><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><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><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o">:=</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="mi">1</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><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">generater</span><span class="p">(</span><span class="o">&</span><span class="nx">wg</span><span class="p">,</span> <span class="nx">ch</span><span class="p">)</span>
</span></span><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">2</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><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">output</span><span class="p">(</span><span class="o">&</span><span class="nx">wg</span><span class="p">,</span> <span class="nx">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="nx">ch</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="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>generater()</code> 関数はチャネルに対して 1 から 10 までの値を吐き出す。
<code>output()</code> 関数はチャネルから値を取り出して表示するという簡単なお仕事である。
ただし <code>output()</code> 関数は2つの goroutine で起動している。</p>
<p>これを実行すると</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run sample1.go
</span></span><span class="line"><span class="cl">Worker 2: 1
</span></span><span class="line"><span class="cl">Worker 2: 2
</span></span><span class="line"><span class="cl">Worker 2: 3
</span></span><span class="line"><span class="cl">Worker 1: 5
</span></span><span class="line"><span class="cl">Worker 1: 6
</span></span><span class="line"><span class="cl">Worker 1: 7
</span></span><span class="line"><span class="cl">Worker 1: 8
</span></span><span class="line"><span class="cl">Worker 1: 9
</span></span><span class="line"><span class="cl">Worker 1: 10
</span></span><span class="line"><span class="cl">Worker 2: 4
</span></span></code></pre></div><p>という出力になった。
2つの goroutine は並行に走ってるので出力順は不定となる。</p>
<p>このコードに <a href="https://pkg.go.dev/golang.org/x/time/rate" title="rate · pkg.go.dev"><code>golang.org/x/time/rate</code></a> パッケージを加えて流量の制御を行う。
こんな感じでどうだろう。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// +build run
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line hl"><span class="cl"> <span class="s">"context"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line hl"><span class="cl"> <span class="s">"sync"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line hl"><span class="cl"> <span class="s">"golang.org/x/time/rate"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">generater</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="nx">ch</span> <span class="kd">chan</span><span class="o"><-</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nb">close</span><span class="p">(</span><span class="nx">ch</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">Done</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}()</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">l</span> <span class="o">:=</span> <span class="nx">rate</span><span class="p">.</span><span class="nf">NewLimiter</span><span class="p">(</span><span class="nx">rate</span><span class="p">.</span><span class="nf">Every</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="o">*</span><span class="mi">2</span><span class="p">),</span> <span class="mi">1</span><span class="p">)</span>
</span></span><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">10</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">l</span><span class="p">.</span><span class="nf">Wait</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">());</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"generater: %v\n"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</span>
</span></span><span class="line hl"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o"><-</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</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><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">output</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="nx">num</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">ch</span> <span class="o"><-</span><span class="kd">chan</span> <span class="kt">int</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">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">ch</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Worker %d: %v\n"</span><span class="p">,</span> <span class="nx">num</span><span class="p">,</span> <span class="nx">n</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="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></span><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><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><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o">:=</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="mi">1</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><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">generater</span><span class="p">(</span><span class="o">&</span><span class="nx">wg</span><span class="p">,</span> <span class="nx">ch</span><span class="p">)</span>
</span></span><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">2</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><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">output</span><span class="p">(</span><span class="o">&</span><span class="nx">wg</span><span class="p">,</span> <span class="nx">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="nx">ch</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="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>これでサイズ 1 のバケットに2秒毎にトークンが挿入される。
トークを取り出すタイミングでチャネルに値を入れるわけだ。
これを実行すると</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run sample2.go
</span></span><span class="line"><span class="cl">Worker 2: 1
</span></span><span class="line"><span class="cl">Worker 1: 2
</span></span><span class="line"><span class="cl">Worker 2: 3
</span></span><span class="line"><span class="cl">Worker 1: 4
</span></span><span class="line"><span class="cl">Worker 2: 5
</span></span><span class="line"><span class="cl">Worker 1: 6
</span></span><span class="line"><span class="cl">Worker 2: 7
</span></span><span class="line"><span class="cl">Worker 1: 8
</span></span><span class="line"><span class="cl">Worker 2: 9
</span></span><span class="line"><span class="cl">Worker 1: 10
</span></span></code></pre></div><p>という感じに2秒毎に結果が出力される。</p>
<p>バケットサイズをプロセッサ数と同数にしてみよう。
こんな感じかな。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// +build run
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><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">"context"</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">"runtime"</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">"time"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"golang.org/x/time/rate"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line hl"><span class="cl"><span class="kd">func</span> <span class="nf">generater</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="nx">ch</span> <span class="kd">chan</span><span class="o"><-</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">max</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nb">close</span><span class="p">(</span><span class="nx">ch</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">Done</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}()</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">l</span> <span class="o">:=</span> <span class="nx">rate</span><span class="p">.</span><span class="nf">NewLimiter</span><span class="p">(</span><span class="nx">rate</span><span class="p">.</span><span class="nf">Every</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="o">*</span><span class="mi">2</span><span class="p">),</span> <span class="nx">max</span><span class="p">)</span>
</span></span><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">10</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="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">l</span><span class="p">.</span><span class="nf">Wait</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">());</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"generater: %v\n"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o"><-</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</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><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">output</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="nx">num</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">ch</span> <span class="o"><-</span><span class="kd">chan</span> <span class="kt">int</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">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">ch</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Worker %d: %v\n"</span><span class="p">,</span> <span class="nx">num</span><span class="p">,</span> <span class="nx">n</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="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></span><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><span class="line hl"><span class="cl"> <span class="nx">max</span> <span class="o">:=</span> <span class="nx">runtime</span><span class="p">.</span><span class="nf">GOMAXPROCS</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><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><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o">:=</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">max</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><span class="line hl"><span class="cl"> <span class="k">go</span> <span class="nf">generater</span><span class="p">(</span><span class="o">&</span><span class="nx">wg</span><span class="p">,</span> <span class="nx">ch</span><span class="p">,</span> <span class="nx">max</span><span class="p">)</span>
</span></span><span class="line hl"><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="nx">max</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><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">output</span><span class="p">(</span><span class="o">&</span><span class="nx">wg</span><span class="p">,</span> <span class="nx">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="nx">ch</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="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>これを実行すると(プロセッサ数:4)以下のようになった。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run sample3.go
</span></span><span class="line"><span class="cl">Worker 3: 3
</span></span><span class="line"><span class="cl">Worker 3: 4
</span></span><span class="line"><span class="cl">Worker 2: 2
</span></span><span class="line"><span class="cl">Worker 4: 1
</span></span><span class="line"><span class="cl">Worker 1: 5
</span></span><span class="line"><span class="cl">Worker 3: 6
</span></span><span class="line"><span class="cl">Worker 2: 7
</span></span><span class="line"><span class="cl">Worker 4: 8
</span></span><span class="line"><span class="cl">Worker 1: 9
</span></span><span class="line"><span class="cl">Worker 3: 10
</span></span></code></pre></div><p>最初の4つは一気に出力されて,以降は2秒ずつの出力。</p>
<p>といった感じで,処理の制限をワーカ側ではなくジェネレータ側で行うのが特徴と言えるだろうか。
Web クローラとか使い道は色々あるかもしれない。</p>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51pUKQajnaL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語による並行処理</a></dt>
<dd>Katherine Cox-Buday (著), 山口 能迪 (翻訳)</dd>
<dd>オライリージャパン 2018-10-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118468 (ASIN), 9784873118468 (EAN), 4873118468 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118468/">Eブック版もある</a>。感想は<a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">こちら</a>。 Go 言語で並行処理を書くならこの本は必読書になるだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-01-13">2020-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語による並行処理 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
time.Ticker で遊ぶ【Go 1.16 バージョン】
tag:text.Baldanders.info,2021-02-18:/golang/ticker-2/
2021-02-18T12:34:25+00:00
2021-12-04T02:40:05+00:00
素敵なキャンセルライフを(笑)
Spiegel
https://baldanders.info/profile/
<p>ずいぶん前に「<a href="https://text.baldanders.info/golang/ticker/" title="time.Ticker で遊ぶ">time.Ticker で遊ぶ</a>」と言う記事を書いたのだが,先日<a href="https://text.baldanders.info/release/2021/02/go-1_16-is-released/" title="Go 1.16 がリリースされた">リリース</a>された <a href="https://go.dev/">Go</a> 1.16 で <a href="https://golang.org/pkg/os/signal/" title="signal - The Go Programming Language"><code>signal</code></a><code>.NotifyContext()</code> 関数が追加された記念に,これを使った改訂版の記事を書いてみたいと思う。</p>
<p><a href="https://text.baldanders.info/golang/ticker/" title="time.Ticker で遊ぶ">前回</a>と同じくお題は以下の通り。</p>
<ol>
<li>一定周期ごとの処理を行う</li>
<li>Ctrl+C 等の割り込み処理を行う</li>
</ol>
<h2>一定周期ごとの処理を行う</h2>
<p>これは<a href="https://text.baldanders.info/golang/ticker/" title="time.Ticker で遊ぶ">前回</a>の記事をほぼそのまま使いまわそう。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// +build run
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><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">"time"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">ticker</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">t</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">NewTicker</span><span class="p">(</span><span class="mi">1</span> <span class="o">*</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">)</span> <span class="c1">//1秒周期の ticker
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">defer</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><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">"Stopping ticker..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">t</span><span class="p">.</span><span class="nf">Stop</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></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">select</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nx">now</span> <span class="o">:=</span> <span class="o"><-</span><span class="nx">t</span><span class="p">.</span><span class="nx">C</span><span class="p">:</span>
</span></span><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="nx">now</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">RFC3339</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><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><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><span class="line"><span class="cl"> <span class="nf">ticker</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>前回でも説明した通り, <a href="http://blog.golang.org/defer-panic-and-recover" title="Defer, Panic, and Recover - The Go Blog">defer</a> 構文を使って終了時に <a href="http://golang.org/pkg/time/" title="time - The Go Programming Language"><code>time</code></a><code>.Ticker.Stop()</code> 関数で周期イベントを止めようとしているが,実際には無限ループなので return まで到達しない(笑)</p>
<h2>NotifyContext 関数で SIGNAL を捕まえる</h2>
<p><a href="https://go.dev/">Go</a> では SIGINT や SIGTERM といった OS から送信される <a href="https://linuxjm.osdn.jp/html/LDP_man-pages/man7/signal.7.html" title="Man page of SIGNAL">SIGNAL</a> をイベントとして <a href="http://golang.org/ref/spec#Channel_types" title="The Go Programming Language Specification - The Go Programming Language">channel</a> に送り込む仕掛けがある(ちなみに Ctrl+C は SIGINT として送られる)。
さらに <a href="https://go.dev/">Go</a> 1.16 では <a href="https://linuxjm.osdn.jp/html/LDP_man-pages/man7/signal.7.html" title="Man page of SIGNAL">SIGNAL</a> イベントを <a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a><code>.Context</code> のキャンセル・イベントとして実装できるようになった。</p>
<p>たとえば,こんな感じに書ける。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// +build run
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><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">"context"</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">"os"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"os/signal"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line hl"><span class="cl"><span class="kd">func</span> <span class="nf">ticker</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">t</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">NewTicker</span><span class="p">(</span><span class="mi">1</span> <span class="o">*</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">)</span> <span class="c1">//1秒周期の ticker
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">defer</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><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">"Stopping ticker..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">t</span><span class="p">.</span><span class="nf">Stop</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></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">select</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nx">now</span> <span class="o">:=</span> <span class="o"><-</span><span class="nx">t</span><span class="p">.</span><span class="nx">C</span><span class="p">:</span>
</span></span><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="nx">now</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">RFC3339</span><span class="p">))</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">case</span> <span class="o"><-</span><span class="nx">ctx</span><span class="p">.</span><span class="nf">Done</span><span class="p">():</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"cancellation from context:"</span><span class="p">,</span> <span class="nx">ctx</span><span class="p">.</span><span class="nf">Err</span><span class="p">())</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</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><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line hl"><span class="cl"><span class="kd">func</span> <span class="nf">run</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">ctx</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">signal</span><span class="p">.</span><span class="nf">NotifyContext</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">(),</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Interrupt</span><span class="p">)</span>
</span></span><span class="line hl"><span class="cl"> <span class="nf">ticker</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span>
</span></span><span class="line hl"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><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><span class="line hl"><span class="cl"> <span class="nf">run</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a> パッケージは並行処理下で使うことが多いだろう。
たとえば <code>run()</code> 関数をこんな感じに書き換えてみるか。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">run</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ctx</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">signal</span><span class="p">.</span><span class="nf">NotifyContext</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">(),</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Interrupt</span><span class="p">)</span>
</span></span><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><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">3</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">n</span> <span class="o">:=</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</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><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">defer</span> <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="nf">ticker</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="nx">n</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><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><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>これで平行に動作している全ての <code>ticker()</code> に対してキャンセルを送り込むことができる。</p>
<p>上のコード例ではひとつの <a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a><code>.Context</code> インスタンスを複数の <a href="http://golang.org/ref/spec#Go_statements" title="The Go Programming Language Specification - The Go Programming Language">goroutine</a> で使いまわしているが,以下のように</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">run</span><span class="p">()</span> <span class="p">{</span>
</span></span><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><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">3</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">n</span> <span class="o">:=</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</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><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">defer</span> <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="nx">ctx</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">signal</span><span class="p">.</span><span class="nf">NotifyContext</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">(),</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Interrupt</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nf">ticker</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="nx">n</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><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><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>各 <a href="http://golang.org/ref/spec#Go_statements" title="The Go Programming Language Specification - The Go Programming Language">goroutine</a> ごとに <a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a><code>.Context</code> インスタンスを生成してセットしても全ての <code>ticker()</code> を <code>Ctrl+C</code> で問題なく止めることができた。</p>
<h2>キャンセル・イベントの伝搬</h2>
<p><a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a> パッケージは,名前の通り,異なるレイヤやドメイン間でコンテキスト情報を受け渡しするためのパッケージだが,親から子にキャンセルイベントが伝搬する性質がある(逆向きには伝搬しない)。
たとえば</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">run</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">parent</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">signal</span><span class="p">.</span><span class="nf">NotifyContext</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">(),</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Interrupt</span><span class="p">)</span>
</span></span><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><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">3</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">n</span> <span class="o">:=</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</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><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">defer</span> <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="nx">child</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">context</span><span class="p">.</span><span class="nf">WithTimeout</span><span class="p">(</span><span class="nx">parent</span><span class="p">,</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Duration</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span><span class="o">*</span><span class="mi">5</span><span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nf">ticker</span><span class="p">(</span><span class="nx">child</span><span class="p">,</span> <span class="nx">n</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><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><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>などとすれば各 <a href="http://golang.org/ref/spec#Go_statements" title="The Go Programming Language Specification - The Go Programming Language">goroutine</a> の <code>ticker()</code> 関数に <a href="https://linuxjm.osdn.jp/html/LDP_man-pages/man7/signal.7.html" title="Man page of SIGNAL">SIGNAL</a> イベントとタイムアウト・イベントの両方を仕込むことができる。</p>
<p>また</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">ctx</span><span class="p">,</span> <span class="nx">cancel</span> <span class="o">:=</span> <span class="nx">signal</span><span class="p">.</span><span class="nf">NotifyContext</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">(),</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Interrupt</span><span class="p">)</span>
</span></span></code></pre></div><p>とした場合の返り値の <code>cancel</code> は関数値になっていて,これをキックすることでペアとなっている <a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a><code>.Context</code> インスタンス(上のコードなら <code>ctx</code>)にキャンセル・イベントを発生させることができる。
実際の使い方として <a href="https://golang.org/pkg/os/signal/" title="signal - The Go Programming Language"><code>signal</code></a><code>.NotifyContext()</code> 関数は main <a href="http://golang.org/ref/spec#Go_statements" title="The Go Programming Language Specification - The Go Programming Language">goroutine</a> に近いところで <a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a><code>.WithCancel()</code> 関数と置き換えることが多いのではないだろうか。</p>
<p><a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a> について詳しくは『<a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go 言語による並行処理</a>』の 4.12 章が参考になる。
素敵なキャンセル・ライフを(笑)</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://mattn.kaoriya.net/software/lang/go/20200916090416.htm">Big Sky :: os/signal に NotifyContext が入った。</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51pUKQajnaL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語による並行処理</a></dt>
<dd>Katherine Cox-Buday (著), 山口 能迪 (翻訳)</dd>
<dd>オライリージャパン 2018-10-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118468 (ASIN), 9784873118468 (EAN), 4873118468 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118468/">Eブック版もある</a>。感想は<a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">こちら</a>。 Go 言語で並行処理を書くならこの本は必読書になるだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-01-13">2020-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語による並行処理 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
Go 1.14 リリース候補版
tag:text.Baldanders.info,2020-02-08:/release/2020/02/go1_14-rc/
2020-02-08T06:33:22+00:00
2021-12-04T02:40:05+00:00
この記事では個人的に気になった点をかいつまんで紹介する。
Spiegel
https://baldanders.info/profile/
<p><a href="https://go.dev/">Go</a> 1.14 のリリース候補版が出た。
これに伴ってリリースノートのドラフト版も更新されたようだ。</p>
<ul>
<li><a href="https://groups.google.com/forum/#!topic/golang-announce/mB1Mp9RlQw8">Go 1.14 Release Candidate 1 is released - Google group</a></li>
<li><a href="https://tip.golang.org/doc/go1.14">Go 1.14 Release Notes - The Go Programming Language</a></li>
</ul>
<p>更にブログでは以下の記事で 1.15 についても言及されている。</p>
<ul>
<li><a href="https://blog.golang.org/go1.15-proposals">Proposals for Go 1.15 - The Go Blog</a></li>
</ul>
<p>詳しくはそれぞれの記事を読んでもらうとして,この記事では個人的に気になった点をかいつまんで紹介する。</p>
<h2>Try 終了のお知らせ</h2>
<p>「<a href="https://text.baldanders.info/release/2019/06/next-steps-toward-go-2/" title="Go 1.13 と 1.14 (Go 2 へ向けて)">Go 1.13 と 1.14</a>」で紹介した <code>try()</code> 組み込み関数の導入は見送られたらしい。</p>
<figure lang="en">
<blockquote><q>Our attempt seven months ago at providing a better error handling mechanism, the <a href="https://golang.org/issue/32437">try proposal</a>, met good support but also strong opposition and we decided to abandon it. In its aftermath there were many follow-up proposals, but none of them seemed convincing enough, clearly superior to the try proposal, or less likely to cause similar controversy</q>.</blockquote>
<figcaption><div>via <q><a href="https://blog.golang.org/go1.15-proposals">Proposals for Go 1.15</a></q></div></figcaption>
</figure>
<p>というわけで,エラー・ハンドリング周りはこれ以上の仕様追加・変更は(1.x の間は)なさそうである。</p>
<h2>埋め込み Interface の改善</h2>
<p><a href="https://go.dev/">Go</a> 1.14 では埋め込み interface の仕様が一部変更になる。</p>
<figure lang="en">
<blockquote><q>Per the <a href="https://github.com/golang/proposal/blob/master/design/6977-overlapping-interfaces.md">overlapping interfaces proposal</a>, Go 1.14 now permits embedding of interfaces with overlapping method sets: methods from an embedded interface may have the same names and identical signatures as methods already present in the (embedding) interface. This solves problems that typically (but not exclusively) occur with diamond-shaped embedding graphs. Explicitly declared methods in an interface must remain unique, as before</q>.</blockquote>
<figcaption><div>via <q><a href="https://tip.golang.org/doc/go1.14">Go 1.14 Release Notes (draft)</a></q></div></figcaption>
</figure>
<p><a href="https://go.dev/">Go</a> では interface は振る舞いのみを定義する型だが,入れ子にすることができる。
こんな感じ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Person</span> <span class="kd">interface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nf">Name</span><span class="p">()</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl"> <span class="nf">Age</span><span class="p">()</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Employee</span> <span class="kd">interface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Person</span>
</span></span><span class="line"><span class="cl"> <span class="nf">Level</span><span class="p">()</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"> <span class="nf">String</span><span class="p">()</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>この例では <code>Employee</code> interface 型に <code>Person</code> interface 型が埋め込まれている。
つまり <code>Employee</code> 型では <code>Name()</code>, <code>Age()</code>, <code>Level()</code>, <code>String()</code> 各メソッドを要求しているわけだ。</p>
<p>ここで <code>Person</code> 型に <code>String()</code> メソッドを付けることを考える。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Person</span> <span class="kd">interface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nf">Name</span><span class="p">()</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl"> <span class="nf">Age</span><span class="p">()</span> <span class="kt">int</span>
</span></span><span class="line hl"><span class="cl"> <span class="nf">String</span><span class="p">()</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>修正された <code>Person</code> 型を使って <code>Employee</code> 型を定義しようとしても <q lang="en"><code>duplicate method String</code></q> とコンパイルエラーになる。
Interface 型の間で定義するメソッドを調整すればいいのだが,他パッケージの interface 型を埋め込む場合は,そのパッケージの仕様変更の影響をモロに受けることになる。</p>
<p>更に</p>
<figure style='margin:0 auto;text-align:center;'><a href="./diamond.puml"><img src="./diamond.png" srcset="./diamond.png 946w" sizes="(min-width:600px) 500px, 80vw" alt="" loading="lazy"></a></figure>
<p>のようなひし形構造になっている場合はより複雑になる。</p>
<p><a href="https://go.dev/">Go</a> 1.14 では(関数型の同一性も含めて)同じメソッドについては重複を許容する。
上述のコード例でもコンパイル・エラーにならないわけだ。</p>
<p>ただし</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">E1</span> <span class="kd">interface</span><span class="p">{</span> <span class="nf">M</span><span class="p">(</span><span class="nx">x</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">E2</span> <span class="kd">interface</span><span class="p">{</span> <span class="nf">M</span><span class="p">(</span><span class="nx">x</span> <span class="kt">float32</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">I</span> <span class="kd">interface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">E1</span>
</span></span><span class="line"><span class="cl"> <span class="nx">E2</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>では(メソッド <code>M()</code> の型が同一ではないので)相変わらずコンパイル・エラーになるようだ。</p>
<h2>Preemptive なスケジューリング</h2>
<p>これは <a href="https://shimane-go.connpass.com/" title="Shimane.go - connpass">Shimane.go</a> の Slack で教えてもらったのだが, <a href="https://go.dev/">Go</a> 1.14 では preemptive (非協調的) なスケジューリング実装になるようだ。</p>
<figure lang="en">
<blockquote><q>Goroutines are now asynchronously preemptible. As a result, loops without function calls no longer potentially deadlock the scheduler or significantly delay garbage collection</q>.</blockquote>
<figcaption><div>via <q><a href="https://tip.golang.org/doc/go1.14">Go 1.14 Release Notes (draft)</a></q></div></figcaption>
</figure>
<p>もともと <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>には,ランタイムによって並列処理の実装詳細を隠蔽することにより,コード記述としての平行処理に注力できるというメリットがあるが preemptive なスケジューリングによって強化されることになる。</p>
<p>ただし全てのプラットフォームで有効になるのではなく</p>
<ul>
<li><code>windows/arm</code></li>
<li><code>darwin/arm</code></li>
<li><code>js/wasm</code></li>
<li><code>plan9/*</code></li>
</ul>
<p>は例外となるらしい。
WebAssembly や Plan 9 が non-preemptive になるのは分かるが, ARM アーキテクチャって実装が難しいのか?</p>
<h2>モジュール対応モード</h2>
<p>モジュール対応モード(module-aware mode)も色々と機能追加されるようだ。
特に <code>vendor</code> ディレクトリとの組み合わせは色々とできそうだ。</p>
<figure lang="en">
<blockquote><q>When the main module contains a top-level <code>vendor</code> directory and its <code>go.mod</code> file specifies go 1.14 or higher, the go command now defaults to <code>-mod=vendor</code> for operations that accept that flag. A new value for that flag, <code>-mod=mod</code>, causes the go command to instead load modules from the module cache (as when no vendor directory is present)</q>.</blockquote>
<figcaption><div>via <q><a href="https://tip.golang.org/doc/go1.14">Go 1.14 Release Notes (draft)</a></q></div></figcaption>
</figure>
<p>この辺は <a href="https://go.dev/">Go</a> 1.14 正式版がリリースされてから試してみよう。</p>
<h2>Launched <a href="https://pkg.go.dev/">pkg.go.dev</a></h2>
<ul>
<li><a href="https://blog.golang.org/pkg.go.dev-2020">Next steps for pkg.go.dev - The Go Blog</a></li>
</ul>
<p><a href="https://pkg.go.dev/">pkg.go.dev</a> は従来の <a href="https://godoc.org/">godoc.org</a> から置き換えることができる。</p>
<figure lang="en">
<blockquote><q>Like <a href="https://godoc.org/">godoc.org</a>, pkg.go.dev serves Go documentation. However, it also understands modules and has information about past versions of a package!</q></blockquote>
<figcaption><div>via <q><a href="https://blog.golang.org/pkg.go.dev-2020">Next steps for pkg.go.dev</a></q></div></figcaption>
</figure>
<p>実際に2020年後半には <a href="https://godoc.org/">godoc.org</a> へのリクエストを <a href="https://pkg.go.dev/">pkg.go.dev</a> にリダイレクトする計画があるらしい。</p>
<figure lang="en">
<blockquote><q>To minimize confusion about which site to use, later this year we are planning to redirect traffic from <a href="https://godoc.org/">godoc.org</a> to the corresponding page on <a href="https://pkg.go.dev/">pkg.go.dev</a></q>.</blockquote>
<figcaption><div>via <q><a href="https://blog.golang.org/pkg.go.dev-2020">Next steps for pkg.go.dev</a></q></div></figcaption>
</figure>
<p>標準パッケージもサードパーティのパッケージも同等に扱えるので,今後は <a href="https://pkg.go.dev/">pkg.go.dev</a> を参照するのがいいかもしれない。</p>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51pUKQajnaL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語による並行処理</a></dt>
<dd>Katherine Cox-Buday (著), 山口 能迪 (翻訳)</dd>
<dd>オライリージャパン 2018-10-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118468 (ASIN), 9784873118468 (EAN), 4873118468 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118468/">Eブック版もある</a>。感想は<a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">こちら</a>。 Go 言語で並行処理を書くならこの本は必読書になるだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-01-13">2020-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語による並行処理 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4908686033?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51RKK5+6bpL._SL160_.jpg" width="112" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4908686033?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Goならわかるシステムプログラミング</a></dt>
<dd>渋川 よしき (著), ごっちん (イラスト)</dd>
<dd>ラムダノート 2017-10-23</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4908686033 (ASIN), 9784908686030 (EAN), 4908686033 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.lambdanote.com/collections/go/products/go-ebook">PDF 版</a>あり。ファイルやソケットなどに代表される順次アクセスの汎化である io.Reader / io.Writer およびその派生・特化クラス,またプロセスやスレッドに関する解説が秀逸だと思う。さらに Docker コアの libcontainer についても解説がある。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2018-10-19">2018-10-19</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Goならわかるシステムプログラミング -->
『Go 言語による並行処理』はEブック版がオススメ
tag:text.Baldanders.info,2020-01-13:/remark/2020/01/concurrency-in-go-digital/
2020-01-13T02:28:13+00:00
2021-08-12T21:22:05+00:00
私も完全に失念していたのだが『Go 言語による並行処理』ってEブック版があるんだよね。
Spiegel
https://baldanders.info/profile/
<p>Twitter で</p>
<figure style='margin:0 auto;text-align:center;'>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">並行(concurrent)と並列(parallel)の違いは『Go 言語による並行処理』できちんと説明されている。 <a href="https://twitter.com/hashtag/golang?src=hash&ref_src=twsrc%5Etfw">#golang</a> で並行処理を書くなら『Go 言語による並行処理』は必読書なので、是非とも手にしていただきたいところである<br> <a href="https://t.co/wvUiI94qOh">https://t.co/wvUiI94qOh</a> <a href="https://t.co/zAkd9anE8u">https://t.co/zAkd9anE8u</a></p>— Der Spiegel im Spiegel (@spiegel_2007) <a href="https://twitter.com/spiegel_2007/status/1214391644616658944?ref_src=twsrc%5Etfw">January 7, 2020</a></blockquote>
</figure>
<p>とか呟いたら微妙に反応があったみたいなので追加情報を記しておく<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>。</p>
<p>つか,私も完全に失念していたのだが『Go 言語による並行処理』ってEブック版があるんだよね。
<a href="https://www.oreilly.co.jp/ebook/">O’Reilly Japan Ebook Store</a> で買える(PayPal 決済)。</p>
<ul>
<li><a href="https://www.oreilly.co.jp/books/9784873118468/">O’Reilly Japan - Go言語による並行処理</a></li>
</ul>
<p>この手の技術解説書を Kindle で買うのは基本的にオススメできない。
理由は大きく2つ:</p>
<ol>
<li>コードをコピペして検証できない</li>
<li>索引が使えない</li>
</ol>
<p>ことである。
まぁ,1番目については,最近では GitHub リポジトリ等にサンプルコードが置かれてたりするのだが。
あと,最初から索引が貧弱な本は技術解説書としては論外。
読み物として面白ければ,それでもいいが。</p>
<p>O’Reilly のEブックは PDF, ePub, mobi の3つのフォーマットで提供されていて,しかも要らん DRM がかかっていない。
適切な PDF リーダ等を使えば語句検索が利用できるし, <a href="https://www.ubuntu.com/" title="The leading operating system for PCs, IoT devices, servers and the cloud | Ubuntu">Ubuntu</a> 環境であれば標準の <a href="https://wiki.gnome.org/action/show/Apps/Evince" title="Apps/Evince - GNOME Wiki!">Evince</a> で充分足りる<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>。</p>
<p>というわけで,『Go 言語による並行処理』を買うならEブック版がオススメという話でした。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">『Go 言語による並行処理』は Go 言語プログラマ必読書だろう</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51pUKQajnaL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語による並行処理</a></dt>
<dd>Katherine Cox-Buday (著), 山口 能迪 (翻訳)</dd>
<dd>オライリージャパン 2018-10-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118468 (ASIN), 9784873118468 (EAN), 4873118468 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118468/">Eブック版もある</a>。感想は<a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">こちら</a>。 Go 言語で並行処理を書くならこの本は必読書になるだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-01-13">2020-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語による並行処理 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4908686033?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51RKK5+6bpL._SL160_.jpg" width="112" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4908686033?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Goならわかるシステムプログラミング</a></dt>
<dd>渋川 よしき (著), ごっちん (イラスト)</dd>
<dd>ラムダノート 2017-10-23</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4908686033 (ASIN), 9784908686030 (EAN), 4908686033 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.lambdanote.com/collections/go/products/go-ebook">PDF 版</a>あり。ファイルやソケットなどに代表される順次アクセスの汎化である io.Reader / io.Writer およびその派生・特化クラス,またプロセスやスレッドに関する解説が秀逸だと思う。さらに Docker コアの libcontainer についても解説がある。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2018-10-19">2018-10-19</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Goならわかるシステムプログラミング -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>「並行性と並列性の違い」については2.1章で3ページ分使って詳しく説明されている。ありがたや。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2">
<p><a href="https://pdfreaders.org/" title="Get a Free Software PDF reader!">Adobe なんて要らん</a>ですよ。偉い人にはそれが分からんのです(笑) いや,真面目な話,官庁が出す PDF を読むのに Adobe Reader をダウンロードさせるのマジで止めて欲しい。特定企業を優遇するとか! <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
saracen/walker で歩いてみる
tag:text.Baldanders.info,2019-10-26:/golang/walking-with-multi-core/
2019-10-26T13:25:35+00:00
2021-12-04T02:40:05+00:00
saracen/walker を使うと filepath.Walk() 関数を置き換えることができる。
Spiegel
https://baldanders.info/profile/
<p>日頃から <a href="https://github.com/mattn/jvgrep" title="mattn/jvgrep: grep for japanese vimmer">mattn/jvgrep</a> には大変お世話になっているので常時 watch しているのだが,最近組み込まれたらしい <a href="https://github.com/saracen/walker" title="saracen/walker: walker is a faster, parallel version, of filepath.Walk">saracen/walker</a> が良さげである。</p>
<p>指定したパス以下のファイル・ディレクトリを探索する機能としては標準の <a href="https://golang.org/pkg/path/filepath/" title="filepath - The Go Programming Language"><code>filepath</code></a><code>.Walk()</code> 関数がある。
たとえば,こんな感じで使う。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">WalkWithSingle</span><span class="p">(</span><span class="nx">rootPath</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="kt">int64</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">lastErr</span> <span class="o">:=</span> <span class="nx">filepath</span><span class="p">.</span><span class="nf">Walk</span><span class="p">(</span><span class="nx">rootPath</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="nx">path</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">info</span> <span class="nx">os</span><span class="p">.</span><span class="nx">FileInfo</span><span class="p">,</span> <span class="nx">err</span> <span class="kt">error</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">info</span><span class="p">.</span><span class="nf">IsDir</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">count</span><span class="p">,</span> <span class="nx">lastErr</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>ちなみにこれは,指定したパス以下に存在する(ディレクトリ以外の)ファイルの数を数える関数である。</p>
<p><a href="https://github.com/saracen/walker" title="saracen/walker: walker is a faster, parallel version, of filepath.Walk">saracen/walker</a> の <a href="https://github.com/saracen/walker" title="saracen/walker: walker is a faster, parallel version, of filepath.Walk"><code>walker</code></a><code>.Walk()</code> 関数を使って <a href="https://golang.org/pkg/path/filepath/" title="filepath - The Go Programming Language"><code>filepath</code></a><code>.Walk()</code> 関数を置き換えることができる。
<a href="https://github.com/saracen/walker" title="saracen/walker: walker is a faster, parallel version, of filepath.Walk"><code>walker</code></a><code>.Walk()</code> 関数の特徴は,ファイル・ディレクトリの探索を並行処理で行うことである。
したがってマルチコアの環境下(最近のパソコンや携帯端末は皆そうだが)ではコア数に応じた高速処理が期待できる。</p>
<p><a href="https://github.com/saracen/walker" title="saracen/walker: walker is a faster, parallel version, of filepath.Walk"><code>walker</code></a><code>.Walk()</code> 関数を使う際にはひとつだけ注意点があって,それは <a href="https://github.com/saracen/walker" title="saracen/walker: walker is a faster, parallel version, of filepath.Walk"><code>walker</code></a><code>.Walk()</code> 関数の引数で指定する関数は goroutine-safe でなければならないということだ。</p>
<p>たとえば<ruby><rb>関数閉包</rb><rp> (</rp><rt>closure</rt><rp>) </rp></ruby>を使って,ついうっかり</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">WalkWithMultiple</span><span class="p">(</span><span class="nx">rootPath</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="kt">int64</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">walker</span><span class="p">.</span><span class="nf">Walk</span><span class="p">(</span><span class="nx">rootPath</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="nx">path</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">info</span> <span class="nx">os</span><span class="p">.</span><span class="nx">FileInfo</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">info</span><span class="p">.</span><span class="nf">IsDir</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">count</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">count</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
<p>なんてなコード書くと,返ってくるファイル数の値は不定になってしまう(どうしてそうなるかは自分で考えよう)。
まぁ,これに限っては <a href="https://golang.org/pkg/sync/" title="sync - The Go Programming Language"><code>sync</code></a><code>/</code><a href="https://golang.org/pkg/sync/atomic/" title="atomic - The Go Programming Language"><code>atomic</code></a> パッケージを使って</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">WalkWithMultiple</span><span class="p">(</span><span class="nx">rootPath</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="kt">int64</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">walker</span><span class="p">.</span><span class="nf">Walk</span><span class="p">(</span><span class="nx">rootPath</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="nx">path</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">info</span> <span class="nx">os</span><span class="p">.</span><span class="nx">FileInfo</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">info</span><span class="p">.</span><span class="nf">IsDir</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">atomic</span><span class="p">.</span><span class="nf">AddInt64</span><span class="p">(</span><span class="o">&</span><span class="nx">count</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><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">count</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
<p>とすれば<ruby><rb>無問題</rb><rp> (</rp><rt>no problem</rt><rp>) </rp></ruby>である。</p>
<p><a href="https://github.com/saracen/walker" title="saracen/walker: walker is a faster, parallel version, of filepath.Walk">saracen/walker</a> の性能評価についてはリポジトリのドキュメントを見てもらうとして,ここではもっとふわっとしたコードで性能差を体感してみよう。
用意したコードは上述した関数をちょっと弄ってこんな感じにしてみた。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><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">"os"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"path/filepath"</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="s">"time"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/saracen/walker"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">WalkWithSingle</span><span class="p">(</span><span class="nx">rootPath</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="kt">int64</span><span class="p">,</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">start</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">lastErr</span> <span class="o">:=</span> <span class="nx">filepath</span><span class="p">.</span><span class="nf">Walk</span><span class="p">(</span><span class="nx">rootPath</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="nx">path</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">info</span> <span class="nx">os</span><span class="p">.</span><span class="nx">FileInfo</span><span class="p">,</span> <span class="nx">err</span> <span class="kt">error</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">info</span><span class="p">.</span><span class="nf">IsDir</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">count</span><span class="p">,</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Since</span><span class="p">(</span><span class="nx">start</span><span class="p">),</span> <span class="nx">lastErr</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">WalkWithMultiple</span><span class="p">(</span><span class="nx">rootPath</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="kt">int64</span><span class="p">,</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">start</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">walker</span><span class="p">.</span><span class="nf">Walk</span><span class="p">(</span><span class="nx">rootPath</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="nx">path</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">info</span> <span class="nx">os</span><span class="p">.</span><span class="nx">FileInfo</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">info</span><span class="p">.</span><span class="nf">IsDir</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">atomic</span><span class="p">.</span><span class="nf">AddInt64</span><span class="p">(</span><span class="o">&</span><span class="nx">count</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><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">count</span><span class="p">,</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Since</span><span class="p">(</span><span class="nx">start</span><span class="p">),</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><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><span class="line"><span class="cl"> <span class="nx">rootPath</span> <span class="o">:=</span> <span class="s">"/usr/local/go/src"</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ct</span><span class="p">,</span> <span class="nx">dt</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">WalkWithSingle</span><span class="p">(</span><span class="nx">rootPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Fprintln</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><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">"WalkWithSingle"</span><span class="p">)</span>
</span></span><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">"\tDuration:"</span><span class="p">,</span> <span class="nx">dt</span><span class="p">)</span>
</span></span><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">"\t Count:"</span><span class="p">,</span> <span class="nx">ct</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">ct</span><span class="p">,</span> <span class="nx">dt</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nf">WalkWithMultiple</span><span class="p">(</span><span class="nx">rootPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Fprintln</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><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">"WalkWithMultiple"</span><span class="p">)</span>
</span></span><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">"\tDuration:"</span><span class="p">,</span> <span class="nx">dt</span><span class="p">)</span>
</span></span><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">"\t Count:"</span><span class="p">,</span> <span class="nx">ct</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>これを実行するとこんな感じになった。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run sample1.go
</span></span><span class="line"><span class="cl">WalkWithSingle
</span></span><span class="line"><span class="cl"> Duration: 38.305071ms
</span></span><span class="line"><span class="cl"> Count: 6008
</span></span><span class="line"><span class="cl">WalkWithMultiple
</span></span><span class="line"><span class="cl"> Duration: 9.328229ms
</span></span><span class="line"><span class="cl"> Count: 6008
</span></span></code></pre></div><p>私のマシンは10年前に買った4コアのパソコンなので,まぁ妥当な値だろう。</p>
<p>数を数えるだけでは芸がないのでファイルの一覧を取得してみようか。
たとえば,以下のような <code>walking.PathList</code> 型を用意する<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">walking</span>
</span></span><span class="line"><span class="cl">
</span></span><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">"sync"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">PathList</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">mutex</span> <span class="o">*</span><span class="nx">sync</span><span class="p">.</span><span class="nx">Mutex</span>
</span></span><span class="line"><span class="cl"> <span class="nx">list</span> <span class="p">[]</span><span class="kt">string</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">New</span><span class="p">()</span> <span class="o">*</span><span class="nx">PathList</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="o">&</span><span class="nx">PathList</span><span class="p">{</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> <span class="nx">list</span><span class="p">:</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">string</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">10240</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></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">p</span> <span class="o">*</span><span class="nx">PathList</span><span class="p">)</span> <span class="nf">Init</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">p</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nf">Lock</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">p</span><span class="p">.</span><span class="nx">list</span> <span class="p">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">list</span><span class="p">[:</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="nx">p</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nf">Unlock</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></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">p</span> <span class="o">*</span><span class="nx">PathList</span><span class="p">)</span> <span class="nf">Append</span><span class="p">(</span><span class="nx">path</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">p</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nf">Lock</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">p</span><span class="p">.</span><span class="nx">list</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">list</span><span class="p">,</span> <span class="nx">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">p</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nf">Unlock</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></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">p</span> <span class="o">*</span><span class="nx">PathList</span><span class="p">)</span> <span class="nf">List</span><span class="p">()</span> <span class="p">[]</span><span class="kt">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">p</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nf">Lock</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">list</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">string</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">list</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="nb">copy</span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">p</span><span class="p">.</span><span class="nx">list</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">p</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nf">Unlock</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">list</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>これを使って先程の <code>WalkWithMultiple()</code> 関数を以下のように書き直してみる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><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">"os"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"sort"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"walking"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/saracen/walker"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">WalkWithMultiple</span><span class="p">(</span><span class="nx">rootPath</span> <span class="kt">string</span><span class="p">)</span> <span class="p">([]</span><span class="kt">string</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">list</span> <span class="o">:=</span> <span class="nx">walking</span><span class="p">.</span><span class="nf">New</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">walker</span><span class="p">.</span><span class="nf">Walk</span><span class="p">(</span><span class="nx">rootPath</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="nx">path</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">info</span> <span class="nx">os</span><span class="p">.</span><span class="nx">FileInfo</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">info</span><span class="p">.</span><span class="nf">IsDir</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">list</span><span class="p">.</span><span class="nf">Append</span><span class="p">(</span><span class="nx">path</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="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">list</span><span class="p">.</span><span class="nf">List</span><span class="p">(),</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><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><span class="line"><span class="cl"> <span class="nx">rootPath</span> <span class="o">:=</span> <span class="s">"/usr/local/go/src"</span>
</span></span><span class="line"><span class="cl"> <span class="nx">list</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">WalkWithMultiple</span><span class="p">(</span><span class="nx">rootPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Fprintln</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><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">"WalkWithMultiple ( Count ="</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="nx">list</span><span class="p">),</span> <span class="s">"):"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">sort</span><span class="p">.</span><span class="nf">Strings</span><span class="p">(</span><span class="nx">list</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">path</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">list</span> <span class="p">{</span>
</span></span><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">"\t"</span><span class="p">,</span> <span class="nx">path</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></div><p>これを実行すると以下のような結果になる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run sample1/sample1.go
</span></span><span class="line"><span class="cl">WalkWithMultiple ( Count = 6008 ):
</span></span><span class="line"><span class="cl"> /usr/local/go/src/Make.dist
</span></span><span class="line"><span class="cl"> /usr/local/go/src/README.vendor
</span></span><span class="line"><span class="cl"> /usr/local/go/src/all.bash
</span></span><span class="line"><span class="cl"> /usr/local/go/src/all.bat
</span></span><span class="line"><span class="cl"> /usr/local/go/src/all.rc
</span></span><span class="line"><span class="cl"> /usr/local/go/src/archive/tar/common.go
</span></span><span class="line"><span class="cl"> /usr/local/go/src/archive/tar/example_test.go
</span></span><span class="line"><span class="cl"> /usr/local/go/src/archive/tar/format.go
</span></span><span class="line"><span class="cl"> /usr/local/go/src/archive/tar/reader.go
</span></span><span class="line"><span class="cl"> /usr/local/go/src/archive/tar/reader_test.go
</span></span><span class="line"><span class="cl"> /usr/local/go/src/archive/tar/stat_actime1.go
</span></span><span class="line"><span class="cl"> /usr/local/go/src/archive/tar/stat_actime2.go
</span></span><span class="line"><span class="cl"> ...
</span></span></code></pre></div><p>よーし,うむうむ,よーし。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://text.baldanders.info/remark/2018/03/grep/">Windows でも Grep したい</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51pUKQajnaL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語による並行処理</a></dt>
<dd>Katherine Cox-Buday (著), 山口 能迪 (翻訳)</dd>
<dd>オライリージャパン 2018-10-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118468 (ASIN), 9784873118468 (EAN), 4873118468 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118468/">Eブック版もある</a>。感想は<a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">こちら</a>。 Go 言語で並行処理を書くならこの本は必読書になるだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-01-13">2020-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語による並行処理 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>配列ではなく連想配列を使うなら標準の <a href="https://golang.org/pkg/sync/" title="sync - The Go Programming Language"><code>sync</code></a><code>.Map</code> 型を使うのがいいだろう。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
Go の疑似乱数生成器は並行的に安全ではないらしい(追記あり)
tag:text.Baldanders.info,2019-09-17:/golang/pseudo-random-number-generator/
2019-09-17T14:27:18+00:00
2022-02-12T19:35:54+00:00
件の記事では解決方法が(具体的には)示されていないので,いくつか対策を考えてみよう。
Spiegel
https://baldanders.info/profile/
<p>面白い記事みっけ!</p>
<ul>
<li><a href="https://qiita.com/hiromichi_n/items/d0636b9444dca18ef357">【Go】rand.Sourceを並列で使いまわすなんて何事だ - Qiita</a></li>
</ul>
<p>折角なので便乗記事を書いてみる。</p>
<p>まぁ,内部状態を持つオブジェクトは,状態が変わらない(immutable)か操作が並行的に安全(concurrency safe)であることが仕様・設計として明確であるものでない限り,複数の goroutine 間でインスタンスを共有してはいけない,というのは基本中の基本である。</p>
<p>ましてや標準の <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language">math/rand</a> パッケージは <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>rand</code></a><code>.Source</code> インタフェースを満たすのであればユーザ側で任意のアルゴリズムを用意することもできるので,並行的に安全であることを期待するほうが間違っているとも言える。</p>
<p>まずは,<a href="https://qiita.com/hiromichi_n/items/d0636b9444dca18ef357" title="【Go】rand.Sourceを並列で使いまわすなんて何事だ - Qiita">件の記事</a>で書かれているコードを挙げておこう。
ただし動作に直接関係ないコードは極力省いている。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><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">"math/rand"</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">"time"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">randSource</span> <span class="p">=</span> <span class="nf">NewRandSource</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">NewRandSource</span><span class="p">()</span> <span class="o">*</span><span class="nx">rand</span><span class="p">.</span><span class="nx">Rand</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</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></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">calcRand</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">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">10000</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">randSource</span><span class="p">.</span><span class="nf">Intn</span><span class="p">(</span><span class="mi">1000</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><span class="line"><span class="cl">
</span></span><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><span class="line"><span class="cl"> <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></span><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">1000</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><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="nf">calcRand</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">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><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><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>ポイントは <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>rand</code></a><code>.Rand</code> インスタンスを初期化時にひとつだけ生成し,複数の goroutine で使い回している点である。
これを実行すると以下のように panic を吐く。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run -trimpath sample.go
</span></span><span class="line"><span class="cl">panic: runtime error: index out of range [-1]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">goroutine 94 [running]:
</span></span><span class="line"><span class="cl">math/rand.(*rngSource).Uint64(...)
</span></span><span class="line"><span class="cl"> math/rand/rng.go:249
</span></span><span class="line"><span class="cl">math/rand.(*rngSource).Int63(0xc000083500, 0x50321535775976c1)
</span></span><span class="line"><span class="cl"> math/rand/rng.go:234 +0x93
</span></span><span class="line"><span class="cl">math/rand.(*Rand).Int63(...)
</span></span><span class="line"><span class="cl"> math/rand/rand.go:85
</span></span><span class="line"><span class="cl">math/rand.(*Rand).Int31(...)
</span></span><span class="line"><span class="cl"> math/rand/rand.go:99
</span></span><span class="line"><span class="cl">math/rand.(*Rand).Int31n(0xc000088090, 0x3e8, 0x1fd)
</span></span><span class="line"><span class="cl"> math/rand/rand.go:134 +0x5f
</span></span><span class="line"><span class="cl">math/rand.(*Rand).Intn(0xc000088090, 0x3e8, 0x1fd)
</span></span><span class="line"><span class="cl"> math/rand/rand.go:172 +0x45
</span></span><span class="line"><span class="cl">main.calcRand()
</span></span><span class="line"><span class="cl"> sample@/sample.go:17 +0x3f
</span></span><span class="line"><span class="cl">main.main.func1(0xc000098000)
</span></span><span class="line"><span class="cl"> sample@/sample.go:26 +0x22
</span></span><span class="line"><span class="cl">created by main.main
</span></span><span class="line"><span class="cl"> sample@/sample.go:25 +0x78
</span></span><span class="line"><span class="cl">exit status 2
</span></span></code></pre></div><p>panic が発生する仕組みは<a href="https://qiita.com/hiromichi_n/items/d0636b9444dca18ef357" title="【Go】rand.Sourceを並列で使いまわすなんて何事だ - Qiita">件の記事</a>に分かりやすく解説されているので参照のこと。</p>
<h2>goroutine ごとにインスタンスを生成する</h2>
<p><a href="https://qiita.com/hiromichi_n/items/d0636b9444dca18ef357" title="【Go】rand.Sourceを並列で使いまわすなんて何事だ - Qiita">件の記事</a>では解決方法が(具体的には)示されていないので,こちらでいくつか考えてみよう。</p>
<p>一番簡単なのは goroutine ごとに <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>rand</code></a><code>.Rand</code> インスタンスを生成することだ。
こんな感じに変えたらどうだろう。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line hl"><span class="cl"><span class="kd">func</span> <span class="nf">calcRand</span><span class="p">(</span><span class="nx">rnd</span><span class="o">*</span> <span class="nx">rand</span><span class="p">.</span><span class="nx">Rand</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">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">10000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">rnd</span><span class="p">.</span><span class="nf">Intn</span><span class="p">(</span><span class="mi">1000</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><span class="line"><span class="cl">
</span></span><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><span class="line"><span class="cl"> <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></span><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">1000</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><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 hl"><span class="cl"> <span class="nf">calcRand</span><span class="p">(</span><span class="nf">NewRandSource</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">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><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><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
<p>これで必要十分に機能するし,少なくとも panic は起こらない。
このやり方の欠点は(goroutine ごとに <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>rand</code></a><code>.Rand</code> インスタンスが生成されるため)元のコードより(僅かだが)高コストになることと,疑似乱数生成器の性能がアルゴリズムだけでなく seed の選び方にも依存する,というあたりだろうか。</p>
<p>まぁ <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language">math/rand</a> の標準アルゴリズム<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> であれば性能に関してはさしたる問題にはならないだろう。</p>
<h2>Generator Pattern を使う</h2>
<p>今回の例ではあまりオススメではないのだが,並行処理の Generator Pattern を使う手もある。</p>
<p>まず <code>NewRandSource()</code> 関数を以下の関数で置き換える。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">NewGenerator</span><span class="p">()</span> <span class="o"><-</span><span class="kd">chan</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span> <span class="o">:=</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">()))</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o">:=</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></span><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">defer</span> <span class="nb">close</span><span class="p">(</span><span class="nx">ch</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o"><-</span> <span class="nx">rnd</span><span class="p">.</span><span class="nf">Intn</span><span class="p">(</span><span class="mi">1000</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><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">ch</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>こうすれば <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>rand</code></a><code>.Rand</code> インスタンスはひとつで済むし(seed もひとつ),持ち回すインスタンスは channel のみなので並行的に安全にできる。
乱数の取り出し側はこう書き換えればよい。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line hl"><span class="cl"><span class="kd">func</span> <span class="nf">calcRand</span><span class="p">(</span><span class="nx">gen</span> <span class="o"><-</span><span class="kd">chan</span> <span class="kt">int</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">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">10000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">if</span> <span class="nx">_</span> <span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="o"><-</span><span class="nx">gen</span><span class="p">;</span> <span class="p">!</span><span class="nx">ok</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</span>
</span></span><span class="line hl"><span class="cl"> <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><span class="line"><span class="cl">
</span></span><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><span class="line"><span class="cl"> <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></span><span class="line hl"><span class="cl"> <span class="nx">gen</span> <span class="o">:=</span> <span class="nf">NewGenerator</span><span class="p">()</span>
</span></span><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">1000</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><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 hl"><span class="cl"> <span class="nf">calcRand</span><span class="p">(</span><span class="nx">gen</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">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><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><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
<p>このコードの欠点は「遅い」ことに尽きる。
まぁ channel の読み書きで同期を取る必要があるから遅くなって当たり前だけど。</p>
<p>今回のようなケースではなく,例えば generator がハードウェア制御を伴うものだったり <a href="https://text.baldanders.info/golang/singleton-pattern/">singleton</a> を含む処理だったり channel の読み書きにかかるコストに対して他の処理が相対的に大きくなったり …などなど,状況によっては Generator Pattern のほうが有利になる場合もあるだろう。</p>
<p>Generator Pattern は平行処理のデザインパターンの中では比較的単純なものだが応用範囲が広い。
<a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>の goroutine 自体は(OS スレッドなどと比べて)かなり安価で手軽に構成できるので,積極的に試してみるといいと思う。</p>
<h3>おまけの追記</h3>
<p>そうそう。
上の <code>NewGenerator()</code> 関数で生成・駆動される goroutine は自力で終了できない。
なので,以下のように</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">NewGenerator</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span> <span class="o"><-</span><span class="kd">chan</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span> <span class="o">:=</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">()))</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o">:=</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></span><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">defer</span> <span class="nb">close</span><span class="p">(</span><span class="nx">ch</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">select</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="o"><-</span><span class="nx">ctx</span><span class="p">.</span><span class="nf">Done</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o"><-</span> <span class="nx">rnd</span><span class="p">.</span><span class="nf">Intn</span><span class="p">(</span><span class="mi">1000</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><span class="line"><span class="cl"> <span class="p">}()</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">ch</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>外部からキャンセルイベントを流し込めるようにするといいかもしれない。</p>
<h2>【2019-09-20 追記】 実は標準で並行的に安全な疑似乱数生成器が用意されていた</h2>
<p>あれから <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language">math/rand</a> のソースコードを眺めてて気がついたのだが,実は並行的に安全な疑似乱数生成器が標準で用意されていた。</p>
<p>たとえば <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>rand</code></a><code>.Intn()</code> 関数を見ると</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// Intn returns, as an int, a non-negative pseudo-random number in [0,n)
</span></span></span><span class="line"><span class="cl"><span class="c1">// from the default Source.
</span></span></span><span class="line"><span class="cl"><span class="c1">// It panics if n <= 0.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">Intn</span><span class="p">(</span><span class="nx">n</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">globalRand</span><span class="p">.</span><span class="nf">Intn</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="p">}</span>
</span></span></code></pre></div><p>とか書かれていて,じゃあ <code>globalRand</code> って何なん? と思って見てみたら</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">lockedSource</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">lk</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Mutex</span>
</span></span><span class="line"><span class="cl"> <span class="nx">src</span> <span class="nx">Source64</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">r</span> <span class="o">*</span><span class="nx">lockedSource</span><span class="p">)</span> <span class="nf">Int63</span><span class="p">()</span> <span class="p">(</span><span class="nx">n</span> <span class="kt">int64</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">r</span><span class="p">.</span><span class="nx">lk</span><span class="p">.</span><span class="nf">Lock</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">n</span> <span class="p">=</span> <span class="nx">r</span><span class="p">.</span><span class="nx">src</span><span class="p">.</span><span class="nf">Int63</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">r</span><span class="p">.</span><span class="nx">lk</span><span class="p">.</span><span class="nf">Unlock</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">r</span> <span class="o">*</span><span class="nx">lockedSource</span><span class="p">)</span> <span class="nf">Uint64</span><span class="p">()</span> <span class="p">(</span><span class="nx">n</span> <span class="kt">uint64</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">r</span><span class="p">.</span><span class="nx">lk</span><span class="p">.</span><span class="nf">Lock</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">n</span> <span class="p">=</span> <span class="nx">r</span><span class="p">.</span><span class="nx">src</span><span class="p">.</span><span class="nf">Uint64</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">r</span><span class="p">.</span><span class="nx">lk</span><span class="p">.</span><span class="nf">Unlock</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">r</span> <span class="o">*</span><span class="nx">lockedSource</span><span class="p">)</span> <span class="nf">Seed</span><span class="p">(</span><span class="nx">seed</span> <span class="kt">int64</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">r</span><span class="p">.</span><span class="nx">lk</span><span class="p">.</span><span class="nf">Lock</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">r</span><span class="p">.</span><span class="nx">src</span><span class="p">.</span><span class="nf">Seed</span><span class="p">(</span><span class="nx">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">r</span><span class="p">.</span><span class="nx">lk</span><span class="p">.</span><span class="nf">Unlock</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></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">globalRand</span> <span class="p">=</span> <span class="nf">New</span><span class="p">(</span><span class="o">&</span><span class="nx">lockedSource</span><span class="p">{</span><span class="nx">src</span><span class="p">:</span> <span class="nf">NewSource</span><span class="p">(</span><span class="mi">1</span><span class="p">).(</span><span class="nx">Source64</span><span class="p">)})</span>
</span></span></code></pre></div><p>とか書かれているわけですよ。
なんだ,ちゃんと <a href="https://golang.org/pkg/sync/" title="sync - The Go Programming Language"><code>sync</code></a><code>.Mutex</code> で排他制御してるんぢゃん。</p>
<p>というわけで,最初のコードは</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><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">"math/rand"</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">"time"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">calcRnad</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">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">10000</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">rand</span><span class="p">.</span><span class="nf">Intn</span><span class="p">(</span><span class="mi">1000</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><span class="line"><span class="cl">
</span></span><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><span class="line"><span class="cl"> <span class="nx">rand</span><span class="p">.</span><span class="nf">Seed</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"> <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></span><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">1000</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><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="nf">calcRnad</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">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><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><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>と書けば panic を吐くことなくちゃんと終了する。
若干遅くはなるけど,それでも Generator Pattern を使うよりは全然速い。</p>
<h2>ブックマーク</h2>
<ul>
<li>
<p><a href="https://hori-ryota.com/blog/golang-channel-pattern/">Go の channel 処理パターン集</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/golang/estimate-of-pi-4-prng/">モンテカルロ法による円周率の推定(その4 PRNG)</a></p>
</li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51pUKQajnaL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語による並行処理</a></dt>
<dd>Katherine Cox-Buday (著), 山口 能迪 (翻訳)</dd>
<dd>オライリージャパン 2018-10-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118468 (ASIN), 9784873118468 (EAN), 4873118468 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118468/">Eブック版もある</a>。感想は<a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">こちら</a>。 Go 言語で並行処理を書くならこの本は必読書になるだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-01-13">2020-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語による並行処理 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language">math/rand</a> パッケージに実装されている擬似乱数生成器は<a href="https://groups.google.com/forum/#!topic/golang-nuts/RZ1G3_cxMcM">ラグ付フィボナッチ法(Lagged Fibonacci Generator)のバリエーション</a>らしい。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
Go 1.12 がリリースされた
tag:text.Baldanders.info,2019-02-26:/release/2019/02/go-1_12-is-released/
2019-02-26T14:03:40+00:00
2021-08-12T21:22:05+00:00
主な変更点としては TLS 1.3 の暫定的なサポートとモジュール・モードの挙動の一部が変わったことだろうか。
Spiegel
https://baldanders.info/profile/
<p>Go 1.12 がリリースされた。
そういえば2月ももう終わりか。</p>
<ul>
<li><a href="https://blog.golang.org/go1.12">Go 1.12 is released - The Go Blog</a></li>
<li><a href="https://golang.org/doc/go1.12">Go 1.12 Release Notes - The Go Programming Language</a></li>
</ul>
<p>主な変更点としては TLS 1.3 の暫定的なサポート(有効にするには環境変数の設定が必要)と<a href="https://text.baldanders.info/golang/go-module-aware-mode/" title="モジュール対応モードへの移行を検討する">モジュール・モード</a>の挙動の一部が変わったことだろうか。</p>
<p>たとえば環境変数 <code>$GO111MODULE</code> を <code>on</code> にしておけば <a href="https://github.com/mattn">mattn</a> さんの <a href="https://github.com/mattn/jvgrep" title="mattn/jvgrep: grep for japanese vimmer">jvgrep</a> をインストールする際にも任意のフォルダで</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go get github.com/mattn/jvgrep@latest
</span></span></code></pre></div><p>とすればよい。
ダミーの <code>go.mod</code> ファイルを作る必要はなくなった。
ブラボー!</p>
<p>Go 1.13 からはモジュール・モードが既定になるようで,「GOPATH モードじゃないと困る」とかじゃなければ環境変数 <code>$GO111MODULE</code> は <code>on</code> のままにしてしまえばいいんじゃないのかなぁ。</p>
<p>あと地味だが嬉しい変更としては,並行処理下で正規表現パッケージ <a href="https://golang.org/pkg/regexp/" title="regexp - The Go Programming Language"><code>regexp</code></a> を使う際に <a href="https://golang.org/pkg/regexp/" title="regexp - The Go Programming Language"><code>regexp</code></a><code>.Regexp.Copy()</code> でクローンを作らなくてもブロッキングが起きないようになった。</p>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a> はこの 1.12 から 1.13 にかけて大きく変わる予感がする(今のところ後方互換性は確保されるだろうが)。
色々と試していって慣れていくのがいいかもしれない。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://text.baldanders.info/golang/go-module-aware-mode/">モジュール対応モードへの移行を検討する</a></li>
<li><a href="https://text.baldanders.info/golang/regular-expression/">正規表現に関する戯れ言</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51pUKQajnaL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語による並行処理</a></dt>
<dd>Katherine Cox-Buday (著), 山口 能迪 (翻訳)</dd>
<dd>オライリージャパン 2018-10-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118468 (ASIN), 9784873118468 (EAN), 4873118468 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118468/">Eブック版もある</a>。感想は<a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">こちら</a>。 Go 言語で並行処理を書くならこの本は必読書になるだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-01-13">2020-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語による並行処理 -->
『Go 言語による並行処理』は Go 言語プログラマ必読書だろう
tag:text.Baldanders.info,2018-11-03:/remark/2018/11/concurrency-in-go/
2018-11-03T00:50:43+00:00
2021-11-28T02:58:44+00:00
並行処理プログラミングが難しいのは,デザイン・パターンの熟成がまだ若いことと,パターンの組み合わせの選択が複雑な点にあると思う。
Spiegel
https://baldanders.info/profile/
<p>やぁ! ついに “<a href="https://katherine.cox-buday.com/concurrency-in-go/">Concurrency in Go</a>” の邦訳版が登場したですよ。
めでたい!</p>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>の特徴はいくつかあるが,大きなものとして「並行処理<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>」を前提とした言語設計が挙げられる。</p>
<p>並行処理では <a href="https://dl.acm.org/citation.cfm?doid=359576.359585">CSP (Communicating Sequential Processes)</a> の成果が取り入れられている。
これが goroutine と channel である。</p>
<p>Goroutine は軽量スレッドなどと呼ばれることもあるが<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>,厳密には coroutine の一種である。
Main goroutine を含む各 goroutine はランタイム・プログラムに組み込まれたスケジューラによって制御される。
つまり実行時の並列処理の詳細はコードレベルでは隠蔽されているのだ。
故にプログラマはコード上の並行処理にのみ注力して記述すればいいことになる。
OS スレッドの仕様がどうなってるとか無駄にデカいスレッドをプールの中でどう使い回すかとか,生産性の欠片もないようなことは考えなくていいわけだ<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>。</p>
<p>Channel は入出力プリミティブで,これによって goroutine 間のメッセージ・パッシング(message passing)を実現している。
たとえば以下のような感じで記述する<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//main goroutine
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">hello</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kd">interface</span><span class="p">{})</span> <span class="c1">//create channel
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span> <span class="c1">//sub goroutine
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">hello</span> <span class="o"><-</span> <span class="s">"Hello, world!"</span> <span class="c1">//send
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}()</span>
</span></span><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="o"><-</span><span class="nx">hello</span><span class="p">)</span> <span class="c1">//receive
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>(<code>go</code> 構文(<a href="https://go.dev/ref/spec#Go_statements" title="The Go Programming Language Specification - The Go Programming Language">go statement</a>)でキックされた関数が sub goroutine となる。関数閉包(closure)になっている点に注目)</p>
<p>これらに加えて,同期をとるための <a href="https://golang.org/pkg/sync/" title="sync - The Go Programming Language"><code>sync</code></a> パッケージやコールグラフの各枝をキャンセルするための <a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a> パッケージが標準ライブラリで用意されている。</p>
<p>メッセージ・パッシングを構成するか <a href="https://golang.org/pkg/sync/" title="sync - The Go Programming Language"><code>sync</code></a> パッケージ等を用いて legacy なメモリアクセス同期を構成するか(あるいはそれらを組み合わせるか)の判断は難しいが,2.4章に大まかな指針が挙げられているので参考になるだろう。
ただし,今まで無理やりメモリアクセス同期で運用していたもののうちかなりのものを軽くて(スレッドセーフという意味で)安全なメッセージ・パッシングに置き換えられるのは確かである。</p>
<p>そうそう。
『<a href="https://www.amazon.co.jp/exec/obidos/ASIN/4873118468/baldandersinf-22/" title="Go言語による並行処理 | Katherine Cox-Buday, 山口 能迪 |本 | 通販 | Amazon">Go 言語による並行処理</a>』では <a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a> パッケージについてページを割いて紹介されているのだ<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>(4.12章)。
<a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a> パッケージをデザイン・パターンとして日本語できちんと紹介している Web 記事や書籍はあまり見かけないので,単純に嬉しい。</p>
<p>並行処理プログラミングが難しいのは,デザイン・パターン(4章で言及されている)の熟成がまだ若いこと,パターンの組み合わせ最適化が複雑なこと,もっと言うなら並行処理の設計は context driven であること,にあると思う(だからこそ <a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a> パッケージは秀逸なのよ)。
デザイン・パターンは(数学の公式と同じく)思考のショートカットなので,そのパターンを構成することの意味を分かった上で適用しないと失敗することが多いんじゃないだろうか。</p>
<p>この本を読んで「よっしゃ,明日から立派な goroutine 使いだ!」とはならないと思うけど,有象無象なコピペ・プログラマじゃなく,きちんと <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>のプログラミングを勉強したいのであれば,この本は必読書になると思う。
少なくとも(立ち読みででも)2章までは熟読すべき。</p>
<p>ところで余談だが,補遺Bは日本語版オリジナルの章だそうだけど,その中に <a href="https://blog.golang.org/go2draft" title="Go 2 Draft Designs - The Go Blog">Go 2 ドラフト</a>で提案されている Generics についてしれっと書かれている。</p>
<figure style='margin:0 auto;text-align:center;'>
<div style="position: relative; margin: 0 2rem; padding-bottom: 56.25%; padding-top: 30px; height: 0; overflow: hidden;">
<iframe class="youtube-player" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;" allowfullscreen frameborder="0" src="https://www.youtube-nocookie.com/embed/6wIP3rO6On8" allowfullscreen></iframe>
</div>
<figcaption><div><a href="https://www.youtube.com/watch?v=6wIP3rO6On8">Go 2 Drafts Announcement - YouTube</a></div></figcaption>
</figure>
<p>次期 <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>に搭載される(かもしれない) Generics についての解説は以下を参考にどうぞ。</p>
<ul>
<li><a href="https://qiita.com/lufia/items/242d25e8c93d88e22a2e">Go 2のgenerics/contract簡易まとめ</a></li>
</ul>
<h2>ブックマーク</h2>
<ul>
<li>
<p><a href="https://mattn.kaoriya.net/software/lang/go/concurrency-in-go.htm">Big Sky :: 書評「Go言語による並行処理」</a></p>
</li>
<li>
<p><a href="http://mattn.kaoriya.net/software/lang/go/20160706165757.htm">Big Sky :: golang の channel を使ったテクニックあれこれ</a></p>
</li>
<li>
<p><a href="https://mattn.kaoriya.net/software/lang/go/20180531104907.htm">Big Sky :: Go 言語の非同期パターン</a></p>
</li>
<li>
<p><a href="http://postd.cc/go_concurrency_visualize/">Go言語の並行性を映像化する | プログラミング | POSTD</a></p>
</li>
<li>
<p><a href="http://qiita.com/tfutada/items/a289628d8b2d0af6152d">Go言語の並行処理デザインパターン by Rob Pike 前編 - Qiita</a></p>
<ul>
<li><a href="http://qiita.com/tfutada/items/dc8db894ac270a79ef2b">Go言語の並行処理デザインパターン by Rob Pike 後編 - Qiita</a></li>
</ul>
</li>
<li>
<p><a href="https://budougumi0617.github.io/2020/02/21/use-context/">context.TODO()を使って漸進的にcontext対応を始める - My External Storage</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/golang/ticker/">time.Ticker で遊ぶ</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/remark/2020/01/concurrency-in-go-digital/">『Go 言語による並行処理』はEブック版がオススメ</a></p>
</li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51pUKQajnaL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語による並行処理</a></dt>
<dd>Katherine Cox-Buday (著), 山口 能迪 (翻訳)</dd>
<dd>オライリージャパン 2018-10-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118468 (ASIN), 9784873118468 (EAN), 4873118468 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118468/">Eブック版もある</a>。感想は<a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">こちら</a>。 Go 言語で並行処理を書くならこの本は必読書になるだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-01-13">2020-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語による並行処理 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>「同時に複数の動作が行われていること」を意味する言葉として「並行(concurrent)」と「並列(parallel)」が混同されることがあるが,プログラミングにおいては,書かれたコードの性質をを表すものを「並行」,動作するランタイム・プログラム(群)の性質を表すものを「並列」と呼んで区別している。両者は密接に関連しているが等価ではない。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2">
<p>OS スレッドに比べて goroutine を駆動する(ランタイム・プログラムが展開する)グリーン・スレッドは非常に軽量らしい。初期のメモリ割当で数キロバイト程度で,実行時に自動的に増減するようだ。 Goroutine のリソースの概算については3.1章で言及されている。 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:3">
<p>ある規模以上のシステムの場合は流量制限等をかける必要があるかも知れない。大規模システム開発での注意点については5章で言及されている。 <a href="#fnref:3" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:4">
<p>受信(<code><-chan</code>)は単項演算子で,送信(<code>chan<-</code>)は送信構文(send statement)で記述する。 <a href="#fnref:4" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:5">
<p><a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a> パッケージはバージョン 1.7 から標準ライブラリに組み込まれたため,古い参考書には載っていない。なお <a href="https://golang.org/pkg/context/" title="context - The Go Programming Language"><code>context</code></a> パッケージにはキャンセルの伝搬以外にもコールグラフ間でデータを受け渡す機能もある。もっともこちらは濫用するとヤバいけど。 <a href="#fnref:5" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
『Go ならわかるシステムプログラミング』を眺める
tag:text.Baldanders.info,2018-10-19:/remark/2018/10/system-programming-in-golang/
2018-10-19T06:31:01+00:00
2021-08-12T21:22:05+00:00
Go 言語でシステム寄りのプログラミングを行うのであれば,是非とも目を通しておくべきだろう。
Spiegel
https://baldanders.info/profile/
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>の言語仕様について勉強するなら真っ先に『<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" title="『プログラミング言語 Go』を眺める">プログラミング言語 Go</a>』を推すが,もう少し実装よりの話であれば『<a href="https://www.amazon.co.jp/exec/obidos/ASIN/4908686033/baldandersinf-22" title="Goならわかるシステムプログラミング | 渋川 よしき, ごっちん |本 | 通販 | Amazon">Go ならわかるシステムプログラミング</a>』を推す。
特に <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>でシステム寄りのプログラミングを行うのであれば,是非とも目を通しておくべきだろう。</p>
<p>この本は <a href="http://ascii.jp/">ASCII.jp</a> で連載されていた「<a href="http://ascii.jp/elem/000/001/235/1235262/" title="ASCII.jp:Goならわかるシステムプログラミング">Goならわかるシステムプログラミング</a>」を書籍用に再構成したものらしい。
なので,まずは Web サイトの方を見て紙の本で買うべきか判断するのがいいと思う。</p>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>の特徴のひとつがクロス・コンパイルの容易さである。
いくつか制約はあるが,基本的には同じコードで Windows も UNIX 系プラットフォームも対応していて,これを実現するために標準の <a href="https://golang.org/pkg/syscall/" title="syscall - The Go Programming Language"><code>syscall</code></a> や <a href="https://golang.org/pkg/runtime/" title="runtime - The Go Programming Language"><code>runtime</code></a> パッケージ周辺を巧妙にカプセル化している。
しかもこれらのソースコードが公開されているため<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> システム・プログラミングの学習教材としても使える<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>。</p>
<p>特に『<a href="https://www.amazon.co.jp/exec/obidos/ASIN/4908686033/baldandersinf-22" title="Goならわかるシステムプログラミング | 渋川 よしき, ごっちん |本 | 通販 | Amazon">Go ならわかるシステムプログラミング</a>』では,ファイルやソケットなどに代表される順次アクセスの汎化である <a href="https://golang.org/pkg/io/" title="io - The Go Programming Language"><code>io</code></a><code>.Reader</code> / <a href="https://golang.org/pkg/io/" title="io - The Go Programming Language"><code>io</code></a><code>.Writer</code> およびその派生・特化クラス,またプロセスやスレッドに関する解説が秀逸だと思う。
さらに Docker コアの <a href="https://github.com/docker/libcontainer" title="docker/libcontainer: PROJECT MOVED TO RUNC">libcontainer</a> についても解説があったりする(自前で <a href="https://github.com/docker/libcontainer" title="docker/libcontainer: PROJECT MOVED TO RUNC">libcontainer</a> を直に触る人はあまりいないかも知れないが)。</p>
<p>個人的によく出来てると思うのが平行(concurrent)/並列(parallel)処理について解説している13章と14章だ。
プロセスやスレッド(更にはガベージコレクション)と <a href="https://golang.org/doc/effective_go.html#concurrency" title="Effective Go - The Go Programming Language">goroutine</a> の関係について日本語で分かりやすく解説している本は少ないと思うので,これだけで『<a href="https://www.amazon.co.jp/exec/obidos/ASIN/4908686033/baldandersinf-22" title="Goならわかるシステムプログラミング | 渋川 よしき, ごっちん |本 | 通販 | Amazon">Go ならわかるシステムプログラミング</a>』を買っておく価値があると思う<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>。</p>
<p><a href="https://golang.org/doc/effective_go.html#concurrency" title="Effective Go - The Go Programming Language">goroutine</a> と channel の組み合わせは並行処理におけるパラダイムシフトとなる可能性がある。
それくらい高いポテンシャルを持っているのだ。
そのための基礎学習を『<a href="https://www.amazon.co.jp/exec/obidos/ASIN/4908686033/baldandersinf-22" title="Goならわかるシステムプログラミング | 渋川 よしき, ごっちん |本 | 通販 | Amazon">Go ならわかるシステムプログラミング</a>』でやっておくのがいいんじゃないかな。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">『Go 言語による並行処理』は Go 言語プログラマ必読書だろう</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4908686033?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51RKK5+6bpL._SL160_.jpg" width="112" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4908686033?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Goならわかるシステムプログラミング</a></dt>
<dd>渋川 よしき (著), ごっちん (イラスト)</dd>
<dd>ラムダノート 2017-10-23</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4908686033 (ASIN), 9784908686030 (EAN), 4908686033 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.lambdanote.com/collections/go/products/go-ebook">PDF 版</a>あり。ファイルやソケットなどに代表される順次アクセスの汎化である io.Reader / io.Writer およびその派生・特化クラス,またプロセスやスレッドに関する解説が秀逸だと思う。さらに Docker コアの libcontainer についても解説がある。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2018-10-19">2018-10-19</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Goならわかるシステムプログラミング -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>の標準パッケージは <a href="https://opensource.org/licenses/mit-license.php" title="The MIT License | Open Source Initiative">MIT ライセンス</a>で公開されている。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2">
<p>ちなみに『<a href="https://www.amazon.co.jp/exec/obidos/ASIN/4908686033/baldandersinf-22" title="Goならわかるシステムプログラミング | 渋川 よしき, ごっちん |本 | 通販 | Amazon">Go ならわかるシステムプログラミング</a>』では,各章の最後に演習問題がある。 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:3">
<p>ただし並行処理のデザインパターン等,もう少し踏み込んだ内容については『<a href="https://www.amazon.co.jp/exec/obidos/ASIN/4873118468/baldandersinf-22/" title="Go言語による並行処理 | Katherine Cox-Buday, 山口 能迪 |本 | 通販 | Amazon">Go 言語による並行処理</a>』のほうがいいかも知れない。 <a href="#fnref:3" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>