BackEnd

Golangのsyncパッケージによる同期・排他制御

投稿日:2020年4月27日 更新日:

はじめに

以前にgoroutineとchannelとContextという記事を書きましたが、今回は channel を使用しないで並行処理の同期や排他制御を簡単に行える、 sync パッケージについて学習したいと思います。

sync.WaitGroup

sync.WaitGroup は複数の Goroutine の完了を待つことが出来ます。

sync.WaitGroup は複数の Goroutine の完了を待つことが出来ます。
sync.WaitGroup は基本的にはただのカウンタですが、カウンタがゼロになるまで処理を待つことができます。上記のコードだと Add(1) でカウンタをインクリメントし、 Done() でデクリメントしています。そして Wait() はカウンタがゼロになるまで待ちます。

sync.Mutex

channel 以外の方法で変数に対して異なる goroutine がアクセスしても、競合によるエラーが起きないようにするための機能です。

sync.Mutex の Lock 関数と Unlock 関数で排他ロックの取得と解除ができます。排他ロックなので、排他ロックを得た goroutine が存在する場合は、ロックを得ようとする他の goroutine は処理を待ち、以下のような結果になります。

sync.RWMutex

sync.RWMutex の Rlock 関数と Runlock 関数で共有ロックの取得と解除ができます。どういうことなのかというと、 Rlock 関数でロックを行なった goroutine 同士であれば処理を進めることができるようになります。また、共有ロックを得た goroutine が存在する場合は、排他ロックを取得しようとする goroutine は待ちます。

実行すると以下のようになります。

sync.Map

Go の map は goroutine で Read しているときに別の goroutine から Write してはいけないというルールがあります。これを行なってしまうと panic が起きてしまいます。例えば以下の処理を実行すると異常終了を起こします。

こちらに対応するには、上記の sync.Mutex を使うことで対応可能ですが、 sync.Map を使用することで、ロックの制御を気にせずに map を使用することができます。

sync.Once

sync.Once は関数を一度だけ実行するようにできます。

実行すると以下のようになります。

sync.Pool

sync.Pool はスレッドセーフなメモリプールです。使い方は、 sync.Pool 構造体を生成する時の New フィールドにオブジェクト生成の関数を指定します。必要時に New の関数が呼ばれます。あるスレッドで、 Get メソッドを呼び、もしプールに無かったら New 関数でオブジェクトを生成します。そして Get でオブジェクトを取得します。もしプールにオブジェクトが在れば、そのオブジェクトを返します。使い終わったら Put メソッドでプールに戻します。
これの繰り返しでオブジェクトをリサイクルすることが出来ます。また、スレッドセーフですので、スレッド間でメモリプールする事ができます。

実行すると以下のようになります。

さいごに

sync パッケージの紹介でしたがいかがでしょうか。一部機能にしか触れられておらず、これからも勉強していこうと思います。

おすすめ書籍

スターティングGo言語 (CodeZine BOOKS) Goプログラミング実践入門 標準ライブラリでゼロからWebアプリを作る impress top gearシリーズ 改訂2版 みんなのGo言語

blog-page_footer_336




blog-page_footer_336




-BackEnd
-

執筆者:


comment

メールアドレスが公開されることはありません。

CAPTCHA


関連記事

laravel logo

Laravelの基礎知識

1 はじめに2 Laravelの概要2.1 学習コストが低い2.2 Symfonyがベース2.3 DIを積極的に活用している3 ディレクトリ構成3.1 app3.2 bootstrap3.3 conf ...

Stripe Connectを使って複合プランの継続課金を実装その2

1 はじめに2 追加プランの作成3 実装3.1 日割り金額の確認3.2 追加プランの契約4 さいごに5 おすすめ書籍 はじめに 前回の記事では、プラン(月額)とユーザ数分のID(従量課金)という2種類 ...

RSpecの個人的Tips集〜その1〜

1 はじめに2 テストコードの実行をスキップする3 共通のテストコードを用意する4 外部APIの返却値をスタブにする5 さいごに はじめに みなさん、テストコードは書かれているでしょうか? 私も極力書 ...

Go言語

Goのfmt.print系関数のまとめ

1 はじめに2 print関数の命名規則3 各print関数の説明3.1 Print(標準出力へ出力)系関数3.2 Sprint(文字列を出力)系関数3.3 Fprint(ファイルへ出力)系関数4 書 ...

Docker上のLaravelのログをFluentdに出力する

1 はじめに2 環境3 Fluentdについて4 目的5 Fluentd本体はdocker-composeで導入5.1 fluentd5.2 db5.3 app5.4 web6 Laravelからログ ...

フォロー

blog-page_side_responsive

2020年4月
 1234
567891011
12131415161718
19202122232425
2627282930  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。