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での資料を読み進める予定です。

2014年5月25日日曜日

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

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

今回はGoのプレゼンテーションツールのpresentの使い方を紹介して頂いた後、Dockerのソースコードを読み進めるという内容になりました。

Goのプレゼンテーションツールであるpresentの使い方は+Takanobu Haginoさんが事前に調べてくれていたので、その結果から使い方を説明していただきました。
インストール方法は、まず、go getを使ってソースコードをダウンロードします。ダウンロード後、go installでコマンドができあがるので準備完了です。

$ go get code.google.com/p/go.tools/cmd/present
$ cd src/code.google.com/p/go.tools/cmd/present
$ go install

その後、プレゼンテーション用のファイルを作成(中身はテキストファイル、フォーマットはmarkdown風)して

$ $GOPATH/bin/present

とするだけで、ローカルにWebサーバが起動しプレゼンテーションを参照する事ができます。このプレゼンテーションツールはプレゼンを表示した状態で、Goのプログラムを動かす事ができるので、いちいち画面を切り替えなくても良いという点では非常に便利です。

ただし、PowerPointとか、Google Presentationのような柔軟な配置が難しいので、凝ったプレゼン資料が作りにくいのも確かです。

後半は、Dockerのソースコードを読み進めました。
今回は、docker versionと、docker runコマンドの2つを読み進めました。
結局、クライアント側を読んだ結果、プロセス通信とHTTPのプロトコルの組み合わせの通信をしているということがわかったので、サーバ側も、各コマンドがリクエストURLから分析した結果から実行する処理が決まるというものでした。

あまり、新しい成果が生まれなかった(Engine構造体とJob構造体がキモというのが変わらない)のと、Docker自体がかなりのペースでMergeとCommitが加わっているので
現状のソースコードを読むことに意味を成さなくなる可能性がでてきました。
(最新のものと比べてかなりの乖離がある)

ということで、最新ソースを追いかけながら読み進める事をすると、Dockerの勉強会になりそうだという判断もあって、次回はGoの資料を読み進める事になりました。

個人的に、ですが、Dockerのソースコードは読みにくい…。と思います。
でも、いい経験になったと個人的に思っているので、人のソースコードを読むのは
間違いじゃないと思います。

最近、Golang Cafe直前になってBlogを書いているので、少し改善したい今日この頃。


2014年5月17日土曜日

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

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

今回は、#27に引き続き、dockerのソースコードを読み進めました。

前回は、deamon側に向かって、リクエストを飛ばすクライアント側のソースコードを読みましたので、docker/docker.goの98行目から開始しました。
(-d、-deamonオプションを付けた場合に動作する部分)

dockerにはHandlerという内部コマンド(?)があって、最初にHandlerを実行するための準備をします。(builtins/builtins.go)内部コマンドはコマンドの名前(例:initserverなど)をキーにして実行する関数を保持するmapとして定義されていて、各処理の時に、名前を指定して呼び出します。
最初は、"initserver"、"init_networkdriver"、"serveapi"の3つが登録されています。

initserverの中で、クライアントからのリクエストに対するHandlerが登録されます。

ただ、読み方としてコツがあって、以前にもでてきた、「goroutinesの切り替わり」を考えて処理の順番を考えないといけません。

したがって、登録したHandlerの順番としては、最初に"serveapi"が実行されます。これは、docker.goの133行目付近はgoroutineになっていますので、バックグラウンドで動くことになります。よって、先にdocker.goの179行目にある、job.Run()が実行されることになります。docker.goを見る限りでは、runtime.GOMAXPROCS()を呼び出していませんのでMAXPROCSは1で動作していますから、「明示的なスレッドのブロック」が無い限りは"serveapi"が動作すると思われます。(ということは、runtime.GOMAXPROCS()を呼び出すとまともに動作しないのかも…?)

job.Run()の中では、登録されているHandlerを呼び出すので、初見では、何かの関数か?と思うかもしれませんが、関数型のmapの関数を呼び出すような仕組みなので、呼び出しの部分は勘違いしないようにしなければいけないと思います。

以前のクライアントからUnixソケットを使って接続するようになっていましたが、docker.goの155行目でacceptconnectionsが実行されています。
(中で、net.DialUnix()されています。(Unixソケットってサーバ、クライアントどちらもDialなのか…?))

正直、dockerのソースコードは読みづらい…。俺だけか?

次回は、各コマンドの内部を読み解いていく予定です。

2014年5月11日日曜日

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

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

今回は前回に引き続き、dockerのソースコードを読もうと思っていたのですが、東京から返ってきた、+Shingo Ishimuraさんの「デプロイツールをGoで」というお題がでて、その検証をしていました。

結局、os/execパッケージのCommandを使って、標準入力と標準出力を取得する。というのがポイントになります。これは、以前のGolang Cafeでもやりました。
ということで、自身満々に

と、言ったのですが、単純なコードだとうまくいくソースコードは書けたのですが、実際にはどうなんだろうか。(業務に係わるものだったので、直接見たわけではないので…)

作成したソースコードはgithubにありますのでごらんください。

今回は、os/execパッケージが主な機能だったので、golangcafeのexecsampleディレクトリに含めてあります。exec.Commandを使うときの参考までに。

それから、その後、今回の内容を活かして、aetesthelperというツールを作ってみました。これは、GAE/Gのgoapp testをサポートするコマンドです。

公式サイトの通りに、goapp testを行えば良いのですが、どうしても、パッケージを分けて、別のパッケージを参照する時に、GOPATH変数を参照して、GOPATH変数で設定したパスの上にファイルがないとテストが動作しない(私だけ?)ので、仕方なく、Tempdir()で作った、ディレクトリにSetenv()して、ファイルを全てコピーして、goapp testを流すという単純な動作にしています。
これで、プロジェクト内の全てのパッケージに対してgoapp testが実行できるので、非常に快適になりました。

次回(と言っても、あと3時間後ですが)は、先々週に引き続いてdockerのdaemon側のソースコードを読みます。