Fumiのブログ

Fumi、Goはじめたってよ。

f:id:fantm21:20190316114552p:plain

はじめに

GoはGoでもポケモンGoではなくて、
Go言語(以下、golang)を使いはじめました\\\٩( 'ω' )و ////

メイン言語をgolangに切り替えていこうかと考えてます。
組み込み用にRustも覚えていきたいけど、ひとまずはgolangを。

golang.org

あと、ハツカネズミのGopherくん可愛いですよね。
CC0 licenseでイラストを公開してくれている人がいたんで共有。
この記事のはじめにいるGopherくんも彼の作品です。
「コヒーでも奢って!」って書いてあるので是非奢ってあげてください! 1杯$5(手数料入れて$5.45)分を自分も奢りました。

github.com

twitter.com

ちなみに、「CC0 license」については以下の記事がわかりやすいです!

creativecommons.jp

はじめた感想

めっちゃC言語っぽい。
まぁ、言語の設計者にケン・トンプソン氏という神様や、その神様と一緒にUTF-8を開発したロブ・パイク氏がいるからね。(ソース元は、Wikipedia)。)

golangではclassがない。これはC++のオブジェクト指向がないのに等しい。 つまり、元々のオブジェクト指向、メッセージパッシング(message passing)が大事という考え方に戻っているように感じた。

ja.wikipedia.org

またgolangのWikipedia)には以下のことが書かれている。

3人の言語設計者すべてが、新しい言語を設計する主なモチベーションとしてC++が好きでないことを共有していたことを述べている

徹底的にC++嫌われているのか。
C++erだった身からすると悲しい...。

やったこと

1. Goのインストール

公式に従えばOK!

golang.org

ただ、VSCodeとかGoLandなどの設定には苦労した。特にVSCode。
$GOPATHというものをubuntuでは$HOME/.bashrc、Macであれば$HOME/.profile、Windowsであればシステム環境設定で設定します。
ただ、これがVSCodeに反映されず、必要なツールをインストールできず、「$GOPATHないぜ」ってエラーをめっちゃ吐かれるという...。

最終的に、VSCodeはelectronで出来ているので、要はChromiumが元になっているからDeveloperToolsが使える。
なので、直接DeveloperToolsのターミナルから環境設定変数に対して$GOPATHを教えたところ上手く動きました。
この為だけに午前中潰れた。

2. A Tour of Go

「A Tour of Go」をやることで、golangってどんな子なのか挨拶程度わかるようになります。

tour.golang.org

「A Tour of Go」をやる際に参考にした記事を貼っておきます。
特に練習問題は自分で解かず、以下の記事の回答を持ってきて、動きについて確認しました。

blog.yuuk.io

3. Go言語関係の記事を読む

たぶんgolangのドキュメントに書いてあるんでしょうけど、
ちょっとまだドキュメントを最初から読む気にはなれなかったのでまずはやっている人の記事を読みました。

コードスタイル

1.Golangでは基本的にキャメルケースを使うことが推奨されています。もちろんスネークケースでも書けますが、Golintをかけるとすべて指摘されるので書く前にこれだけは覚えておきましょう。
2.頭文字を大文字にするとpublicな変数、小文字にするとprivateな変数になります。
インターンを開催して分かったGolangを書き始める人に知っておいてほしい事 – Eureka Engineering – Medium」より引用

golangでは、キャメルケースが推奨されているんですね。
C#みたい。

標準ライブラリの豊富さ

標準ライブラリが整備されている (vs. C++)
むしろ標準ライブラリにjsonのparserすら存在しないC++がおかしい…
なぜGo言語 (golang) はよい言語なのか・Goでプログラムを書くべき理由 | yunabe.jpより引用」

golangはめっちゃ標準ライブラリが整備されててびっくりしました。
ただ、量が多いからどのライブラリにどうゆう機能があるのかを把握するのは大変です。

goroutineについて

golangの特徴でもある、並列・並行処理なのですが、以下の特徴があります。

goroutineの起動にもコストがかかってしまうこと
コストがかさむと雪だるま式にパフォーマンスが劣化してしまうこと
これらの特徴を考えると、goroutineの扱いは慎重にならなければなりません。
golangを使って開発したWebAPIを1年半運用して改善してきたことー月間20億PVのマンガサービス開発の裏側 | Nagisaのすゝめ」より引用

まぁ、golangはHDLのようにFPGA上で動かすものではなく、CPU上で動くのでそうでしょうね。

Go の並行処理モデルの方針は下記に宣言されています。

"Do not communicate by sharing memory; instead, share memory by communicating" 「Go の並行処理 - Block Rockin’ Codes」より引用

「シェアメモリを使って通信はせず、通信をすることによってメモリを共有するんだ」というのはなるほどって感じですね。
channelとか完全にこれですよね。

Goroutine とは
・Coroutine ではない。
・Thread, Process でもない。
・複数の Thread 上に多重化されて実装されてる。
・main() 自身や Scavenger(GC) などランタイムも goroutine を使ってる。
Go の並行処理 - Block Rockin’ Codes」より引用

Threadではない? どうゆうこと?
ということで他の人の記事も当たってみました。

qiita.com

qiita.com

qiita.com

「軽量スレッド」という言葉が上の記事の中では出てきますね。
さらに記事に貼られていたgolang公式のFAQでは以下のように書かれていました。

Why goroutines instead of threads?
Goroutines are part of making concurrency easy to use. The idea, which has been around for a while, is to multiplex independently executing functions—coroutines—onto a set of threads. When a coroutine blocks, such as by calling a blocking system call, the run-time automatically moves other coroutines on the same operating system thread to a different, runnable thread so they won't be blocked. The programmer sees none of this, which is the point. The result, which we call goroutines, can be very cheap: they have little overhead beyond the memory for the stack, which is just a few kilobytes.

To make the stacks small, Go's run-time uses resizable, bounded stacks. A newly minted goroutine is given a few kilobytes, which is almost always enough. When it isn't, the run-time grows (and shrinks) the memory for storing the stack automatically, allowing many goroutines to live in a modest amount of memory. The CPU overhead averages about three cheap instructions per function call. It is practical to create hundreds of thousands of goroutines in the same address space. If goroutines were just threads, system resources would run out at a much smaller number.
Frequently Asked Questions (FAQ) - The Go Programming Language」より引用

以下、Google翻訳結果。

なぜスレッドの代わりがgoroutineなのか?
ゴルーチンは並行性を使いやすくするためのものです。 しばらく前からあり続けてきたアイデアは、独立して実行している関数(コルーチン)を一連のスレッドに多重化することです。 ブロッキングシステムコールの呼び出しなどによってコルーチンがブロックされると、ランタイムは同じオペレーティングシステムスレッド上の他のコルーチンを自動的に別の実行可能スレッドに移動するので、それらはブロックされません。 プログラマーはこれのどれも見ない、それがポイントである。 我々がゴルーチンと呼ぶ結果は非常に安くなることができます:それらはスタックのためのメモリを超えて少しオーバーヘッドを持っています、それはほんの数キロバイトです。

スタックを小さくするために、Goの実行時はサイズ変更可能な境界スタックを使います。 新しく発見されたゴルーチンは数キロバイトを与えられます、それはほとんどいつも十分です。 そうでない場合、ランタイムはスタックを自動的に格納するためにメモリを増やし(そして縮めて)、多くのゴルーチンが適度な量のメモリで生きることを可能にします。 CPUオーバーヘッドは、関数呼び出しあたり平均3つの安価な命令です。 同じアドレス空間に何十万ものゴルーチンを作成するのは実用的です。 ゴルーチンが単なるスレッドであるならば、システムリソースはずっと少ない数で使い果たされるでしょう。
Google 翻訳」より

つまり、goroutineは適切なスケジュールをシステムに対して(※)登録していて、それをプログラマがやる必要はないんだと。
あと、スタックを小さくしているからメモリ消費も少なくて、
CPUオーバーヘッドも3つくらいの命令でやりとりしてるからオーバーヘッドも減るようにしてるんだぜ!って感じかな? ちなみに、「システムに対して(※)」としたのは、CPUへの設定の話なのか、OSへの設定の話なのか分からないため。 (追記) 組み込みじゃないんだから、CPUのレジスタを直接いじらないで、OSのスケジューラに対して行うのか?

qiita.com

ということで、この記事が一番適切に書いてる気がする。

依存管理ツール

dep は Go が公式に "実験的に" 作っている依存管理ツールです.
glide など以前から存在していたツールからの migration の仕組みも持っており,dep への移行を促すプロジェクトも多いです. 「Go 1.11 の modules・vgo を試す - 実際に使っていく上で考えないといけないこと #golang | Wantedly Engineer Blog」より引用

クロスコンパイル

私としては、一番これがgolangを魅力に感じさせました。
Javaとかでもクロスコンパイル出来ますが、あくまであれはJava VM上。 これは実行ファイルを各OS毎に吐き出してくれます。便利!

qiita.com

まぁ、上記の記事にあるように「コンパイルしたい対象の環境ごとに、準備が必要」みたいですが、
いずれそこも公式に自動化されるんではないかと期待したいです。
(ドキュメント読んでないからどう設定するのか、自動でできるものなのかは知らないけど。)

4. socket周りのアプリを作る

最近はsocket周りのアプリをいつも作っているので、早速golangで作ってみよう!
っと思って公式ドキュメントをみに行きました。

golang.org

f:id:fantm21:20190316113413p:plain

golangに慣れたと思った私がバカでした。
もう少し修行してきます。
ということで、とりあえず「先人に学べ」。まずはすでに実装したって記事を読んでいきました。

kudohamu.hatenablog.com

kuroeveryday.blogspot.com

cuto.unirita.co.jp

だいぶこれでgolangと遊べる友達になった気がします!!

f:id:fantm21:20190316114650p:plain

5. webアプリを作る

socket通信に比べたらめっちゃ簡単でした!
ただ、自分がまだ慣れていないだけどすが、やっぱり公式ドキュメントはちょっとわかりづらい。

golang.org

qiita.com

studio-andy.hatenablog.com

liginc.co.jp

f:id:fantm21:20190316115152g:plain

6. デスクトップアプリを作る

これは作るというより、demoを動かしたなんですが、動かすまでがたくさん罠があって大変だった。
こちらは別途違う記事として後日書きます。

とりあえず、使っているフレームワークだけ貼っておきます。

github.com