GoConnect#0 レポート

自分がイチから主催した初イベント「Go Connect #0」を4/11に開催しました。

gotalk.connpass.com

speakerdeck.com

データ

参加者

概要 人数
申込者数 29人
参加者 18人
キャンセル済み 7人
無断キャンセル 4人

参加率は62%でした。
ですが、キャンセルをきちんとしてくれる人が多くて助かりました。
当日の開始直前に参加登録をし結局来ない方もいらっしゃいましたが、どういう背景なのか気になるところです。

登壇

登壇の申し込みは4件、登壇時間はすべて5分でした。
(その他、自分が登壇2件、スポンサーLT1件でした。)

Go Connect では発表者が発表時間を自由に選べるようにしていましたが、5分が人気のようです。

収支

今回は参加費を取らなかったので赤字です。(想定通り)
飲食付きのイベントは1回約3万円で開催できるようです。
ピザを別のもので置き換えるともう少し安くあがるかもしれません。
Go Connect でもピザではなくまい泉のミニバーガーを検討していましたが、配送時間の都合が付けられなく断念しました。

アンケート結果

統計データのみ

非常に良い結果をいただいています。

食べ物・飲み物ともにあるほうが良いようです。
一方でアルコール提供については意見が割れているようです。
実際にイベントでも想定以上にソフトドリンクが人気でした。

ふりかえり

良かったこと

まず大きな失敗や問題が無かったことが良かったです。

また、交流を重視したイベントでしたが、発表時間外はワイガヤな雰囲気を醸成できたのが良かったです。

取り組んだ工夫としては

  • スキマ時間にBGMを流す
  • スライドに話題の例を出す
  • 色々な人に話しかける

あたりをしましたが、そちらが効果が出たかなと思いました。
また、会場の方がアイコンとIDの書かれた名札を作ってくださったのでそちらもありがたかったです。

改善すること

発注量は完全にミスったので次回からは調整していきたいですね。

  • ソフトドリンク:2倍必要
  • お菓子類:半分でいい
  • ピザ:半分でいい
  • アルコール:半分でいい

あたりでしょうか。

次回挑戦すること

次回からは有料にしていきたいと思います。
毎回自分の財布から3万円飛んでいかせるわけにもいかないので・・・

もちろん飲食のスポンサー企業を募るという手もありますが、「スポンサーがいないと開催できない」という状態は避けたいので今のところスポンサー企業を募る予定はありません。

Goの勉強 テスト

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

go test ツール

  • go test はテストドライバ。
  • _test.go で終わるファイルは go build ではビルド対象には含まれず、 go test ではビルド対象に含まれる。
  • _test.go には以下のものを書くことができる。
    • Test で始まる関数はテスト関数
    • Benchmarkで始まる関数はベンチマーク関数
    • Exampleで始まる関数はコード例関数
  • go test を実行するとこれらの関数を探し、一時的なmainパッケージを生成して実行する。

Test関数

func TestName(t *testing.T) {  
        // ...  
}  
  • Name は省略可能である。
  • パラメータtはテストの失敗を報告するメソッドを提供する。
    • t.Errorまたはt.Errorfを使用する。
  • go test -v で実行時間を表示できる。
  • go test -run で実行するテストを正規表現で指定できる。
  • Goのテストでは表駆動を使用する場合が多い。
  • テストが失敗しても後続のテストは実行される。
    • 本当にテストを止めたい場合には t.Fatalt.Fatalfを使用する。
  • テストの作成者はテストの失敗の原因を究明しなければいけないプログラマに役立つように努めるべきである。
  • テストの都合でパッケージ循環が起きるケースがあり、その場合のために外部テストパッケージがある。
    • 外部パッケージはそのパッケージの名前に _test をつけた名前になる。
  • go list を使うことで、ビルド時にそのパッケージに含まれるファイルを調べることができる。
    • go list -f={{.GoFiles}} package_name でビルド時に含まれるファイルのリストを出力する。
    • go list -f={{.TestGoFiles}} package_name でテストファイルのリストを出力する。
    • go list -f={{}.XTestGoFiles} package_name で外部テストファイルのリストを出力する。
  • 外部テストパッケージでその対象パッケージの非公開要素にアクセスするために、_test.goに公開要素のみを書くことがある。慣習的に export_test.go という名前を付ける。

カバレッジ

  • テストはその性質上、バグが存在しないことを証明できない。
  • テストがどの程度テスト対象のパッケージを動かしたかをカバレッジと呼ぶ。
  • カバレッジ定量化できず、あくまでカバレッジが有効であるというのは経験則である。
  • ステートメントカバレッジはテスト中に1回は実行される文のソース中での割合である。
  • go test -run=FuncName -coverprofile=c.out PackageNameカバレッジを収集できるようにし、
  • go tool cover -html=c.out で結果をブラウザで見ることができる。

Benchmark 関数

  • ベンチマークは固定した負荷のもとでプログラムの性能を測定することである。
  • ベンチマーク関数は関数名を Benchmark ではじめ、 *testing.B を引数にとる
func BenchmarkMethod(b *testing.B) {  
    for i := 0; i < b.N; i++ {  
        Method()  
    }  
}  
> go test -bench=.  
goos: darwin  
goarch: arm64  
pkg: pkg/name  
Method-10         6738589               160.8 ns/op  
PASS  
ok      pkg/name       1.854s  
  • 以下を示している。
    • GOMAXPROCS が 10 だった。
    • 関数の呼び出しを6738589 回実行した結果の平均が 168.0 ns だった。
  • -benchmem オプションを付けるとメモリ割り当ての情報も表示できる。

プロファイル

  • プロファイリングとは、プロファイルイベントをサンプリングし、そのイベントから性能を推定することである。
  • プロファイリングは重要なコードを特定するために用いられる。
  • イベントの統計情報をプロファイルと呼ぶ

  • Go では以下の種類のプロファイルをサポートしている。

    • CPUプロファイル: CPU時間を最も必要とした関数を特定する。OSからの割り込みから再開された際にイベントを作成する。
    • ヒーププロファイル: 最も多くのメモリを割り当てた文を特定する。512KBのメモリ割り当てにつきイベントを作成する。
    • 待ちプロファイル: 最もゴルーチンを待たせたものを特定する。ゴルーチンが待たされるごとにイベントを作成する。
  • 以下のコマンドでプロファイルを収集できる。
    • go test -cpuprofile=cpu.out
    • go test -blockprofile=block.out
    • go test -memprofile=mem.out
  • プロファイルオプション付きでテストが実行されると、実行ファイルが末尾.testで保存される
  • プロファイルの解析にはpprofが必要である。
go test pprof -text -nodecount=10 ./package.test ./cpu.log  

Example関数

  • Example で始まる関数はコード例を示す。
  • コード例はコンパイル時に検査されるため、古くなりにくい。
  • ExampleFunctionName は関数のコード例を示し、 Example はパッケージ全体のコード例を示す
  • コード例の最後に // Output: のコメントがある場合、その関数が標準出力に出力した内容とコメントの内容が一致するかが検査される。

Goの勉強 パッケージとGoツール

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

  • Goではパッケージが導入されていて、パッケージを通して再利用可能になっている。
  • 公開されたパッケージは http://godoc.org で確認できる。

導入

  • パッケージの目的は、他のパッケージとは独立に、関連する機能を、変更や理解が容易にできる単位にまとめることである。
    • モジュール性という。
  • 個々のパッケージは独自の名前空間を定義するため、他のパッケージの名前と衝突しない。
  • パッケージは可視性を利用してカプセル化を提供する。
  • ファイルを変更すると、そのファイルの含まれるパッケージ全体を再コンパイルしないといけない。
  • Goのコンパイラは他の言語のコンパイラよりも速い
    • import文が先頭にあることで、ファイルをすべて読み込まなくても依存関係がわかるため。
    • 循環がないため並列にコンパイルできるため。
    • コンパイルされたオブジェクトファイルが依存先の情報も記録しているため。

インポートパス

  • import 宣言にあるインポートパスによってパッケージを一意に特定できる。
  • 言語仕様上、インポートパスの決定方法を定義しておらず、各ツールに任せている。
  • この章ではgoツールを前提にする。
  • 標準ライブラリ以外のパッケージは名前衝突を避けるために、パッケージ名をインターネットドメイン名から始めるべきである。

パッケージ宣言

  • package 宣言はすべてのGoファイルの先頭に必須である。
  • 慣習的にパッケージ名はインポートパスの最後の部分になる。
  • ただし、以下は例外である。
    • mainパッケージ。
    • ファイル名が_test.goで終わる場合、パッケージ名も_testで終わることができる。
      • つまりディレクトリに2つのパッケージを置くことができる。
    • インポートパスにバージョン番号がある場合、パッケージ名はそのバージョン番号を取る。

インポート宣言

  • Goファイルではpackage宣言の直後に0個以上のimport宣言を書くことができる。
  • 同じ名前を持つパッケージをインポートする場合、改名インポートが使用される。
    • 改名インポートはそのファイルにのみ影響を与える。同じパッケージの別ファイルには影響を与えない。
import (  
        "crypto/rand"  
        mrand "math/rand"  
)  
  • 改名インポートは衝突がない場合でも役立つ。
    • 自動生成されたコードのパッケージ名が扱いづらいとき。
    • パッケージと同じ名前のローカル変数名を多く持ちたいとき。

ブランクインポート

  • パッケージをインポートする必要はあるが、そのパッケージを呼び出さない場合、ブランクインポートをする必要がある。
import _ "image/png"  
  • これはパッケージで定義されている変数の初期化やinit関数を実行するために使用される。
  • 例えば image.Decodeはデコードできる形式を登録する必要がある。これはimage/jpegimage/pngのinit関数で行っている。
  • 同じように、database/sqlで使用できるドライバは各ライブラリのinit関数で登録される。

パッケージと命名

  • パッケージ名は
    • 簡潔でかつ意味がとおるようにする。
    • 説明的でかつ曖昧にならないようにする。
    • 単数形にする。
    • 他の意味を持つ名前を避ける。
      • 例: "temp": temperature, temporary
    • ローカル変数で使われる名前を避ける。
  • パッケージのメンバー名は
    • パッケージ名合わせて意味が通るようにする。
    • 単一の型を提供する単一型パッケージrand.Randなど重複しないように注意する

Goツール

  • goツールは
    • パッケージマネージャである。
    • ビルドシステムである。
    • テストドライバである。

ワークスペースの構成

パッケージのダウンロード

  • go get を使うことでインターネット上のパッケージもインストールできる。
  • go getGitHubなどの有名なホスティングサイトをサポートしており、Gitのようなバージョン管理システムをサポートしている。
    • つまり、単なるファイルコピーではなくクライアントである。
  • インポートパスとホスティングされているファイルのドメイン名は必ずしも一致しない。
    • インポートパスにHTTPアクセスをするとHTMLが返り、その中の <meta name="go-import">ホスティングの情報が書かれている。
    • 例: <meta name="go-import" content="golang.org/x/net git https://go.googlesource.com/net">

パッケージのビルド

  • go build
    • 引数に渡されたパッケージをコンパイルできる。
      • パッケージがライブラリ(main以外)の場合はコンパイル結果は破棄される。
      • パッケージがmainの場合はリンカが呼ばれ、実行ファイルが作成される。
      • パッケージはインポートパスや . で始まる相対パスで指定できる。
      • カレントディレクトリに実行ファイルが生成される。
    • 引数でファイル名を指定することもできる。
      • go build をしてそのファイルを実行するためのコマンド go run がある。
      • .go で終わっていない引数はプログラムへの引数として解釈される。
  • go install
  • go buildgo install は1度実行されると、それ以降変更されていない場合はコンパイルを実行しない。
  • net_linux.go などOSやアーキテクチャ名の入っているファイルは、それをターゲットにしている場合のみコンパイルされる。
  • 以下のようなビルドタグをパッケージ宣言の前に書くことでビルドを制御できる
// +build linux darwin  
// +build ignore  

パッケージのドキュメント化

  • パッケージのAPIにはドキュメンテーションコメントを書く慣習がある。
  • コメントは宣言名から始まる要約文になる。
  • コードと同様にドキュメンテーションも簡潔性と単純さが好まれる。
  • パッケージのドキュメンテーションコメントはdoc.goという名前のファイルに書かれることが多い。
  • go docを使うとドキュメントを参照できる。
    • 完全なインポートパスや大文字小文字を必要としない。(最後の例)
go doc time  
go doc time.Slice  
go doc time.Duration.Seconds  
go doc json.decode  
  • godoc コマンドを使うとドキュメントを表示するWebサーバを立ち上げることができる。
godoc -http :8000  

インターナルパッケージ

  • インポートパスにinternalが含まれている場合、go buildはそのパッケージを特別に扱う
  • 例えば、net/http/internal/chunkednet/http/httputilnet/httpからは参照できるがnet/urlからは参照できない。

パッケージの問い合わせ

  • go list を使うと利用可能なパッケージを調べることができる。
  • ワイルドカード ... を使用できる。
  • -jsonJSON形式で出力できる。
  • -f を使うと template/text のテンプレートで出力形式を定義できる。
go list -f '{{join .Deps " "}}' strconv  

認定スクラムマスターを取得しました

認定スクラムマスターを取得しました!やったー!

背景

去年知ってビックリしたのは、アジャイルスクラムに詳しくない人の中には、スクラムマスターを資格の名前だと思っている人がまぁまぁいるということ。
ギャップを埋めるために「資格の名前じゃないんですよ」と説明することもできますが、自分が資格を取ってしまうのもアリだなということで、重い腰をあげて資格取得に動きました。

研修選び

認定スクラムマスターを取得するためには研修を受ける必要がありますが、僕はアトラクタさんの研修を選びました。
前提知識なしで選んでいたので、ネームバリューというか、有名な方が多くいらっしゃったことが主な理由です。
また、最近はオンライン研修が多く、現地参加型の研修が少なかったというのもあります。
オンラインよりも現地のほうが楽しそうですし、学びも大きそうだなと感じています。(実際にそうだったように思います。)

学習

学習としては、スクラムガイドを読み直したのと、SCRUM MASTER THE BOOK を購入して読みました。
あとはRSGT2024への参加も学習の一環として行ったのですが、これは認定スクラムマスターの勉強の域をだいぶ越えていそうでした。(が、それはそれとして面白く、学びも多かったです。 RSGT2024参加レポート

研修

研修は箱根の研修施設で2泊3日で行われました。
研修の内容はもちろん書けませんが、自分の知りたかったことを多く学べたし、自分の気付いていない視点も重要であることがわかったので非常に満足でした。
他の参加者の方と広くお話できたのも良かったです。これはオンラインだと難しそう。


(まるで素材のような我々)

試験

試験は日本語で受けましたが、少し難しかったです。
もしかして英語だとわかりやすいのか?と思う問題もチラホラ。
結果は92/100点でした。
どの問題を間違えたかは教えてくれるのですが、正答は教えてくれず・・・
学習のために教えてほしい!!

まとめ

ということで、無事に資格を取れました。
資格を取れたということも嬉しいし、そこまでの過程での学習も実のあるものになって良かったです。
SEUちゃんと計上していこう。

『偶然同じ』という奇跡は頻繁に起こるのか?

ポエム。
フロントエンドは事情が違いそうなので、バックエンドの話と捉えてください。

DRYの原則について調べるとたいてい出てくる『偶然同じ』処理に注意せよという話がいっぱい出てくる。
つまり、何かをまとめようとしたときにそれはまとめるべきではなく、『偶然同じ』処理な場合があると言う話だ。

この話自体にはもちろん完全同意なのだが、一方でこの考えを免罪符のように使ってないだろうか?

自分の作ってるプロダクトを思い浮かべてほしい。あなたのプロダクトには、この「たまたま『偶然同じ』だった」という奇跡が何個あるだろうか?(つまり、プロダクトコードにある重複コードの数だ。)

「世の中って奇跡にあふれてるんだなぁ」みたいな考え方になることもできるが、僕はどちらかというと「これは本当に奇跡なんだろうか?」と疑うようにしている。
そしてじっくりと考えてみると、「『偶然同じ』処理だった」ではなく「抽象化に失敗していた」というケースが多い。
抽象度をひとつ上げて考えたり、リフレーミングしてみると解決できたりする。
またはそれがドメインに由来するものなら、ドメイン知識を持っている人と議論したほうが良いかもしれない。ドメイン知識を蒸留できるチャンスだ。

ということで、「『偶然同じ』処理には気をつけよう。それが本当に『偶然同じ』なのか、抽象化の失敗なのかはしっかりと考えたほうがいい。」というのを最近思っている。

Regional Scrum Gathering Tokyo 2024 に参加してきた

掲題のとおり、通称RSGT2024に参加してきました。

2024.scrumgatheringtokyo.org

色々と衝撃的なイベントだったので、まとめようと思います。

チケットが手に入らない

発売日の2日後に現地チケットを購入しにいったら売り切れてました。
オンラインチケットは売っていたのでオンラインチケットを購入。

このままオンラインで観るかーと思ってたところ、開催2日前に「現地に行けなくなりチケットを譲りたい」という方がいて、譲っていただきました。ありがとうございます!


ということで、幸運で現地に行くことができました。来年はチケット争奪戦がんばろうと思います。

day0の繋がり

開催前日にオンラインのイベント?があり、知り合いを増やすワークショップに参加しました。
後述するRSGTの性質上、自分のようなソロ初参加勢は知り合いがおらず、当日のギャザリングの壁が高いのでとてもありがたかったです。

開催2日目にday0メンバーに声をかけ、一緒にランチをさせてもらいました。

ここから、一緒にセッションをきいたり、終わった後の雑談などもしやすくなったので、本当にday0に感謝です。

ギャザリングへの情熱がすごい

当日の朝、会場に行って一番驚いたのは、すでにみんな受付のまわりでワイガヤと参加者同士でお喋りしてるということ。
そして会場のほうは閑散としていて、誰も席に座っていません。
自分が参加してきた今までのカンファレンスだとあさイチでお喋りしてる人なんて少数で、みんな会場の席に座ってパソコン開いている人ばかりだったので衝撃的でした。
そして当日の朝に限らず、みんな「隙あらば会話」といった感じで人と話しているのです。すごい!
これは2日目の昼間に撮った写真ですが、廊下の奥までみんな会話しているのがわかると思います。

自分はひとりで初参加だったので知り合いも多くないので「誰かと会話する」というのは少しハードルが高かったのですが、勇気を持って話しかけるとみなさんフレンドリーに接してくれ、みなさんの暖かさに感動しました。

そしてもちろん、夜の懇親会でもギャザリングしてたわけですが、discordのテキストチャットやボイスチャットでもギャザリングがされており、深夜帯まで無限に動いていて凄かったです。

セッションのレベルが高い

色々なセッションに参加してきましたが、どれもレベルが非常に高かったです。
スケジュールに「Begginer Session」とあっても、全然ビギナーレベルじゃない感じでした。

全体的に「価値」や「大規模スクラム」に関するセッションが多かったように思います。

レベルは高いですが、得るものや考えたいことが多くあり、非常にタメになるお話が多かったです。
特にキーノートの2セッションはもう一度振り返りたいです。

そしてもちろん、セッションだけでなくギャザリングの内容もレベルが高かったです。
いくつかその中で気づきもあったので良かったです。

夜が長い

これは他のカンファレンスも同じですが。
これは僕が開催場所である御茶ノ水or秋葉原を去った時間です。

  • 1日目: 23:50
  • 2日目: 22:40
  • 3日目: 28:30

そして、2日目以外は途中抜けしていますし、2日目も終わった後に他と合流しに行った人もいたそうです。すごい。

イベントによって夜の長さは違います。RSGTは初参加だったのでとりあえず同じ3日間開催のPHPerKaigiと同じくらいだろうと見積もっていましたが、だいたい同じくらいでした。
ただ最終日の夜に「First Time Attendee でこの時間までいるのは変人ですよ」と言われました。そんなことないです、ただの一般人です。

まとめ

まとめると「最高だった」ということです。
来年も行きたいですし、今度はスクフェスにも参加してみたい!

Goの勉強 共有された変数による並行性

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

競合状態

  • あるゴルーチン内のイベントxと別のゴルーチン内のイベントyがあり、xとyのどちらのイベントが先に発火するか不明な場合、xとyは並行であると言う。
  • ある関数が2つ以上のゴルーチンから同期なく呼び出しても正しく動作を続ける場合、その関数は並行的に安全と言う。
  • ドキュメントで型が並行的に安全であると述べられている場合に限り、並行に変数へアクセスすべきである。
    • そうでない場合は単一のゴルーチンに閉じ込めるか、相互排他の高度な不変式を維持する必要がある。
  • パッケージレベルの変数は並行的に安全であることが期待される。
  • データ競合は、2つのゴルーチンが同じ変数へ並行にアクセスし、かつ書き込みがある場合に発生する。
var x []int  
go func() { x = make([]int, 10) } // *1  
go func() { x = make([]int, 100000) } // *2  
x[99999] = 1  

とした場合、1 でスライスのポインタが設定され、2でスライスの長さが設定されるかもしれない。
この場合、基底配列は10の長さしかないため、関係のないメモリを更新してしまう可能性がある。
これを 未定義な振る舞い と言う。

データ競合を回避する方法は3つある。

  • データを変数へ書き込まない
  • 複数のゴルーチンからの変数へのアクセスを避ける
    • ゴルーチンに閉じ込められた変数へのアクセスを仲介するゴルーチンのことをモニターゴルーチンと言う
    • パイプラインを用いて変数を共有した際に、次のステージへ渡した後にその変数にアクセスしないのであれば、アクセスが逐次的になる。この方法を順次閉じ込めと言う。
    • 複数のゴルーチンからの変数へのアクセスを許可するが、一度に単一のゴルーチンだけにアクセスさせる。
      • 相互排他と言う。

相互排他:sync.Mutex

  • 同時実行を制御するためのチャネルを計数セマフォと呼び、その中でも1までしか数えないセマフォバイナリセマフォと言う。
  • このパターンの実装として sync.Mutex がある。
var (  
    mu      sync.Mutex  
    balance int  
)  

func Deposit(amount int) {  
    mu.Lock()  
    balance = balance + amount  
    mu.Unlock()  
}  
  • LockUnlock の間の領域をクリティカルセクションと言う。
  • 上記のように関数・ミューテックスロック・変数を扱うことをモニターと言う。
  • sync.Mutex は再入可能ではないため、二重に呼び出すことはできない。
  • 対応策として、公開関数と内部関数に処理を分ける方法がある。
func Deposit(amount int) {  
    mu.Lock()  
    defer mu.Unlock()  
    deposit(amount)  
}  

func deposit(amount int) {  
    balance += amount  
}  

func Withdraw(amount int) bool {  
    mu.Lock()  
    defer mu.Unlock()  
    deposit(-amount)  
    if balance < 0 {  
        deposit(amount)  
        return false  
    }  
    return true  
}  

リード/ライトミューテックス:sync.RWMutex

  • sync.Mutex のロックを使用する場合、読み込み同士でもロック待ちが発生してしまう。
  • sync.RWMutex.RLock() を使用することで、共有ロックを取得でき、読み込み同士であればロック待ちが発生しない。
  • sync.Mutex.Lock() でロックが取得されている間は sync.RWMutex.RLock() は待たされることになる。

メモリの同期

うーん、わからんかった。

  • 同期をすることにより、タイミングだけでなくメモリの状態も同期することができる。
  • 同期をしない場合、一方で設定した値をもう一方で取得できるとは限らない。
    • CPUコアが複数ある場合など、メモリの持ち方や参照のされ方はハードウェアに依存する。

遅延初期化: Sync.Once

  • コストの高い初期化ステップを必要になるまで遅延させることがある。
  • 一方でそういった処理は並行的に安全に書くコストが高い。
  • Goでは Sync.Once を使って初期化処理を簡単に書くことができる。
var loadIconsOnce sync.Once  
var icons map[string]image.Image  

func Icon(name string) image.Image {  
        loadIconsOnce.Do(loadIcons)  
        return icons[name]  
}  

競合検出器

  • 並行性のミスを発見するための動的解析ツールである競合検出器がGoランタイムにある。
  • --race オプションを付けることで使用できる。
  • 競合検出器はデータ競合をレポートするが、実行時に発生したデータ競合しか検出できない。

ゴルーチンとスレッド

伸長可能なスタック

  • OSのスレッドはたいてい2MBのスタックと呼ばれるメモリ領域を確保する。
    • スタックは実行中の関数呼び出しやローカル変数が保存されている活動領域。
  • 2MBの領域は大きすぎるし、小さすぎる。
    • 簡単な計算しかしないものについては2MBは大きすぎる。
    • ネストの深い複雑な関数を呼び出しているものについては2MBは小さすぎる。
  • ゴルーチンはたいてい2KBのスタックで活動する。
  • ただし、必要に応じて領域を拡張したり縮小したりできる。
  • ゴルーチンのスタックの大きさの制限は1GBである。

ゴルーチンのスケジュール

  • OSスレッドはOSカーネルによってスケジュールされる。
    • 定期的にハードウェアタイマーがプロセッサに割り込み、スケジューラを起動させる。
    • スケジューラは現在のスレッドを一時停止させ、次に実行されるスレッドを調べる。
    • 別のスレッドを実行する必要がある場合は、メモリ上にレジスタの情報を保存し、実行するスレッドのレジスタ情報をメモリから読み込む。
  • OSスレッドは頻繁にメモリの読み書きが発生する。
  • Goのランタイムはm個のゴルーチンをn個のOSスレッドで多重化する。(m:nスケジューリング
    • 時間単位ではなく、 time.Sleep やチャネルの操作があるとスケジューリングを行う。

GOMAXPROCS

  • 能動的に実行できるOSスレッド数を GOMAXPROCS で設定できる。
    • デフォルトはCPU数。
    • ちなみに僕のマシンのCPUは10個でした。
  • runtime.GOMAXPROCS関数を使うか、環境変数を設定することによりこの値を変更できる。
    • 引数に-1を渡すと設定を変えずに現在の値を見ることができる。
  • 以下のゴルーチンはGOMAXPROCSの管理に含まれない。
    • スリープしていたり、通信で待たされているゴルーチン。
      • こちらはそもそもOSスレッドを必要としない。
    • I/Oや他のシステムコール、Goで書かれていない関数呼び出しをしているゴルーチン。

ゴルーチンは識別子を持たない

  • 一般的なマルチスレッドサポートのプログラミング言語では、スレッドに識別子を持たせている
  • これをキーにしたグローバルなマップをスレッドローカル領域と呼び、スレッドごとに独立した値を保存している
  • Goではこの識別子をプログラマが知る手段を提供していない
    • なぜなら乱用されがちだから