2014年6月28日土曜日

Golang Cafe #35を開催しました。

Golang Cafe #35を開催しました。

今回は、GoCon 2014 Springの時に発表されたDave Cheneyさんの資料
読み進めました。

今回の資料は、「Goのプログラムを早くする5つのこと」ということで話されたようです。
最初、参加者の全員が思っていたと思うのですが、「Goのプログラムを早くするために”プログラマ”がすればいいこと」が書かれていると思っていました。

しかし、中身は「Goのコンパイラがコードを解析してコンパイルしてリンクする時にやっていること」が書かれているようでした。
しかも、結構深い内容で、読む方も疲れてしまいました。(私だけかもしれませんが)

5つのうち、2つ目までを読み進めたので、そのまとめを書いておきます。

1つ目は"value"
ポイントは、Goでは、例えばint32の変数だと、正確に4バイトが確保されます。
ですが、Pythonだと、24バイト。Javaだと、16バイト(32bit版)か32バイト(64bit版)が確保されます。同じ、4バイト変数なのに。

で、これが重要な理由はなにか?というと、CPUとメモリのバスの速度差がでてくるようになった背景があって、メモリの転送時間がCPUの処理時間に比べて長いので、CPUが転送待ちになってしまうので、処理速度が上がらないわけです。

そこで、キャッシュの機構をCPUとメモリの間にいれてやれば早くなるわけですが、キャッシュの領域もそこまで大きくない。

ということで、コンパクトな構造体を作り、余計な間接部分を避けるようにGoのコンパイラが良いようにしてくれている。
コンパクトなデータ構造はキャッシュをしっかり使える。
これにより、より良いパフォーマンスを発揮できるようになっている。

ということでした。

2つ目は"inlining"
ここでのポイントは関数呼び出しをインライン化すること。
デッドコードの除去。

1つ目の関数呼び出しのオーバヘッドは回避できないので、Goのコンパイラはinline化できるものは、勝手にinline化しているようです。これにより、関数呼び出しのオーバーヘッドをなくしています。ですが、inline化は、「コピペ」であるわけですから、バイナリサイズは大きくなってしまいます。速度を求めるために、バイナリサイズが大きくなる事に目をつぶっているわけですね。
(個人的には、バイナリサイズが大きくなるとは言え、1ファイルになるのはいいことだと思うけど…。こだわりがある人はまた違う見解があるんだろうか。)

そして、デッドコードの除去に関しては、if(false) { ... }となるようなケースだと、「絶対にif文の中を通らないわけですから、なくしても構わない。ということで、思い切ってコンパイル時には外しているようです。
したがって、Debug用コードを書く場合は、単純にDebugフラグをtrueにして、本番環境ではDebugフラグをfalseにした状態にしてビルドすればいいわけです。
(ただし、オプション引数によってtrue/falseを切り替えるケースでは、デッドコードにならないので、除去されません。)

今回は、結構深くて重たい資料だったと思うのですが、がんばって読んでみると良いものだと思います。が、これは業務とかに利用するのは難しい気が…。

次回は、Google I/O 2014が終わったので、いろんな動画やCodelabの資料が公開されてきているので、動画を見たり、Codelabの資料を追いかける予定です。
(ただし、Goのセッションは今年はなかった…)







2014年6月19日木曜日

Golang Cafe #34を開催しました。

Golang Cafe #34を開催しました。

今回はhtmlday 2014の一環として開催しましたので、GAE/Goのチュートリアルを進めてみました。

内容は

  1. 開発環境の構築
  2. Hello World
  3. ユーザ認証
  4. FormからのPOST
  5. データストアの使い方
  6. deploy
という流れで、私が以前執筆した書籍の頃からあまり変化はなく、GAE/Goに関してはGoの変化に対して大きく変わっていないというのがわかりました。

本当は、世界の+Ryuji IwataさんがGAE/Pythonを使われているようなので、解説をお願いしたかったのですが、どうしても遠慮したいということだったので、未熟者の私が少し解説をさせていただきました。

Hello Worldは、text/plainのデータを出力しますので、文字コードが化ける事があるようでした。ブラウザがShift-Jisで表示しようとしてしまう(?)ようなので、本番では、<meta charaset="UTF-8" />とか、httpヘッダに文字コードを設定するなどが必要になります。

ユーザ認証のためのappengine/userパッケージがGoogleの認証をそのまま利用できる優れもので、アプリケーションを作るときには非常に便利なのですが、実際使われているケースは少ないのかもしれません…。(独自認証とか、OAuthを使うとか…)

FormからのPOSTは単純なPOSTの処理と、リクエストパラメータを表示させるだけのものですが、html/templateを使って、htmlを出力させています。
html/templateはAngularJSと相性があまり良くない気がする…。({{と}}を使うので。)
ちゃんとこの時に、<!DOCTYPE html>をつけてhtml5感を出しておきました。

データストアの使い方に関してはGetとPutだけで、Goのノウハウとは違ってくるのですが、話題としては色々話したと思います。

最後のdeployまでは私はしませんでしたが、+Hideki Matsudaさんは実行されたのかな?と思いますが、コマンドとしては、appcfg.pyのフロント側なので、特に難しい所は無いと思います。(appcfg.pyもまだ使えます)

また、GAE/Goを扱ったりしてみたいと思っているのである程度資料を読んだら
戻ってくることにしようと思います。

次回は、GoConの資料の後で公開されたものを読み進める予定です。


2014年6月15日日曜日

Golang Cafe #33を開催しました。

Golang Cafe #33を開催しました。

今回はGo Conference 2014のKeynoteの資料のGo: 90% Perfect, 100% of the time.を読み進めました。この資料はKeynoteなので、「Goは良いよ」という事が書かれていました。他の言語と比べてのGoの評価もあっておもしろいのですが、ちょっと評価が高過ぎるかな?と思えましたが、Keynoteなのでその辺は少し大きく表現しているのかもしれませんね。

Camlistoreという会社でのGoの導入までの話がつらつらと書かれていましたが、以前はPerlと、C、たまにJavaという感じでアプリケーションを開発していたけど、Perlとかだと、Callback地獄になってしまうのでちょっと面倒という話がありました。
Goだと、ある程度軽減できるようです。

気になるキーワードとしては、
Framework:gorilla、martini、Revelなど
net/httpの標準ライブラリ
nginxが不要な標準httpサーバ
libpng、imagemagickが不要(Goにはimage/pngパッケージがあるので)
pure goでpng、jpeg、gifのエンコード、デコードができる。
標準ライブラリでの暗号化
シェルスクリプトの置き換え

ということで、Go良いよ。という話題を見て終わりました。

次回は、htmldayの一環として、GAE/Goをやりま「した。」
またblogを書きます…。



2014年6月3日火曜日

Golang Cafe #32を開催しました。

Golang Cafe #32を開催しました。

今回は、先日東京で行われたGo Conference 2014 Springの発表資料をみんなで読むという回になりました。

一番まとまってそうな+Yoshifumi YAMAGUCHIさんのBlogから資料を遡っていきました。

読み進めた順に話を進めていくと、

  1. 300万人をGoで捌いた話 // Speaker Deck
  2. Do not communicate by sharing memory - Google ドキュメント
  3. Go in Production at Mackerel.io // Speaker Deck
  4. Martini - Web framework for Go
  5. pt&Goroutines // Speaker Deck

300万人をGoで捌いた話の資料を見てみると、goroutinesとchannelを使って、通信させて、リクエストを受けたgoroutineはDBアクセスなどの重たい処理を極力させないようにしてレスポンスを返すという主旨の内容だったと感じます。
恐らくchannelについてもバッファ付きチャネルを使って、チャネルにデータが来るのを待ち続けるgoroutineとchannelにデータを送るgoroutineに分かれているのだろうという想像をしました。
スピーカーがどういう話をしたかはわからないのですが、話の方向性としては、重たい処理をgoroutineでバックグラウンドで処理をさせておくようにしようという話になりました。

Do not communicate by sharing memoryは、簡単にいうと、複数のgoroutinesからいわゆる「グローバル変数」へのアクセスはやめよう。という事が書かれていると認識しました。変数でアクセスするぐらいならchannelでデータのやり取りをしよう。という感じです。どうしても変数へのアクセスが必要なら、sync.Mutexとか、sync.WaitGroupを使った同期を考えないといけません。

Mackerel.ioは、Mackerel-agentがGoで書かれていて、agentについての話です。
資料の中にはtimeパッケージを使ったchannelの通信なんかも書かれていますので、参考にしてみて下さい。

Martiniの話は恐らくMartini自体の紹介だと思いますが、このFWは便利そうな気がします。Goの場合、現状ではrouting部分は必ず書かないといけないので、書き方が簡単になるならいいんじゃないのかな?と思ったりします。ここで、ORMについての話も出てきて、どれかの資料に書いてあった、gorpが便利というTweetとか、投稿を見た(気がする)ので、Martini+gorpでDBを使ったアプリケーションを開発すると良いのかもしれません。

最後のpt&Goroutinesは、「今日のまとめ」的な資料で、goroutineとchannelを使った並列化が焦点になっていると思います。Goでの並列処理を考える時には、Goroutineの切り替わりと、channelのバッファを考えないと高速化できないのですが、(channelのバッファが1だと、入ってくるまで取り出す側がブロックされる)バッファについても言及されているので良かったです。

今回は、ちょうど前回やった、「シダ植物」の並列化のお題と被ったお陰で、いろんな並列化についての議論ができて良かったと思います。ネックになる所と、Goroutineの切り替わりが発生する処理が全くない場合など、深いお題だったと皆さん感心されていました。さすが、世界の+Ryuji Iwataさん。

おまけですが、「シダ植物」の計算量もN=25あたりになると応答が無くなるぐらい計算量が上がるそうです。

次回は、GopherCon 2014の資料を読み進める予定です。

2014年6月1日日曜日

Golang Cafe #31を開催しました。

Golang Cafe #31を開催しました。

最近、次の回とBlogを書く回が何回目だったかよくわからなくなる今日このごろです。
それぐらい長い長い運営が続いているようです。(Blogを書くのは31回目で、次回(今日)が32回目です。)
本来は、「私が適当にコードを書くために時間を強制的に確保するためのネタ」だったのですが、今では、常に4人集まる「巨大イベント」になってしまいました。

さて、今回は、+Takanobu Haginoさんがいらっしゃらなかったので、Blog記事を読み進めるというのはやめて、世界の+Ryuji Iwataさんがお書きになった「プログラムでシダを描画する」をGoで描画するをGoroutineを使って高速化しようということにしました。
流れでそうなってしまいました。

今回のソースコードはgithubにあげていますのでそちらもごらんください。
shida.goがとりあえず、関数f()の呼び出しをgoroutineに入れておくパターンで作り、
shida2.goはif文が付くものと、必ず呼び出されるものの大きく2つにわける形でgoroutineに登録したものです。

結果として、shida.goを実行すると、N=11あたりで、panicが発生して描画することができなくなりました。で、改善(?)したものもやっぱりN=11あたりでpanicが発生してしまいました。もう少し、検証を進めてみたいと思ったのですが、時間があまり取れなかったので、進めることができませんでしたが、恐らく、登録数が多すぎてオーバーフローしているのではないか?と当日は考えていました。

が、今、ちゃんとログを見てみると、panic: runtime error: index out of range
ということなので、何か違う問題がありそうです。

で、原因が、math/rand/rng.goで発生しているので、じっくりと見てみると、
rng.feed--とか、計算している場所がありました。ほぼ確実に、マルチスレッドのブロックがないので、GOMAXPROCS(4)とかで動かしていると配列エラーになりそうな予感がします。ということで、goroutineの登録が多すぎたのではなくて、randで乱数を生成するときの配列の添字がマイナスになってしまうのが原因のように感じられました。

ということで、今回のポイントは「randとgoroutineを組み合わせる時は、しっかり排他処理をしましょう」ということでした。

2014/06/02追記:
Golang Cafe #32でも並列化についての話題が議論となり、私のshida3.goでは、goroutineの終了を取りこぼしている可能性があることに気が付きました。
結局、sync.WaitGroupを使って、カウントを取ることと、バッファ付きChannelを使って、終了を待ち受けるような構成にしなければいけないだろうという話になりましたが、
そもそも、goroutineの切り替わりが発生しない処理ばかりなので、実際にどこで切り替わるの?ということも考えないといけないことになりました。その点については、runtime.GOMAXPROCS()で同時実行数を変更することで、並列処理されるから、問題はないのでは?という話になったり…。+Ryuji Iwataさんのお題は実は難しかった。と再認識させられる結果になりました。

次回(今日)は、5/31のGo Conferenceでの資料を読み進める予定です。