2014年11月2日日曜日

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

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

今回は、isuconという「与えられたサーバとそこで動作するWebアプリケーションを高速化してアクセス数を競うイベント」の予選問題でGolangが使われたという情報を聞いたので、実際に挑戦してみようという主旨で開催しました。

本来はAMIというAWSで動作するイメージを使ってAWSにデプロイして競うようなのですが、「課金前提」ということで、GCEに…というのもやめまして、ローカルにデプロイしようと頑張ってみました。

最初、「Dockerを使おう」ということで、

$ docker pull mysql

としたのですが、これが大失敗。関連する全てのコンテナをダウンロードし始めて、1時間待ってもダウンロードが終了しなかったので(Wimax回線の調子が悪かった…?)ローカルのhomebrewを使ったインストールに切り替えました。

$ brew update
$ brew install mysql

これで、mysqlがインストールできたので、早速ログインしてバージョンを確認します。

$ mysql.server start

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.6.20    |
+-----------+
1 row in set (0.03 sec)

インストールが完了したので、次にinit.shを動かしました。
すると、"MySQL server has gone away"というメモリ不足で発生するエラーに悩まされました。
drupalのblogに設定の記載例があったのでそれを元に、my.cnfを修正しました。
ただし、table_cacheという設定はないようで、そのままコピペしても改善しませんでした。実際に編集する時はtable_cacheの行は書かないようにしましょう。

[mysqld]

# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M

# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin

# These are commonly set, remove the # and set as required.
# basedir = .....
# datadir = .....
# port = .....
# server_id = .....
# socket = .....
skip-external-locking
key_buffer = 384M
max_allowed_packet = 64M
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 64M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size = 32M
max_allowed_packet = 32M
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M 

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 

これでinit.shを実行した所、今度は、

ということになったので、いろいろ試行錯誤した結果、+0900という記載がダメなようなので
$ sed -e s/\+0900//g dummy_log2.sql

として、+0900の記述を消してから登録しました。homebrewでインストールした時のtimezoneがJSTになっていたので、これをUTCに変えてやればそんなことをしなくても良さそうな気がしてきました。が、本来の主旨と違う気がしたのでそこまで検証していません。

次に、Webサーバの起動ですが、Goの場合は、アプリケーションにhttpサーバの機能があるので、go buildして、起動するだけです。
$ cd webapp/go
$ ./build.sh
$ ./golang-webapp

これで、http://localhost:8080に接続すると「いすこん銀行」が表示されるはずです。

次に、ベンチマーク用コマンドもGoで書かれていますので、go buildすればいいのですが、makefileが用意されているので、それに従ってコンパイルします。
中身を見ると、標準でAWSにリクエストを飛ばすようになっているので、
$ cd benchmarker
$ make debug

として、コンパイルします。すると、localhostに対するリクエストになります。
ですが、そのままだと、http://localhostへのリクエストになり、goのwebappにリクエストが送信されないので、main.goの81行目付近を書き換えます。

    cli.StringFlag{
     Name:   "host",
     Value:  "localhost:8080",
     Usage:  "Bench Endpoint host",
     EnvVar: "ISUCON4_BENCH_HOST",
    },

これでビルドしなおせばローカルホストに対するリクエストが送信されるようになり、スコアも表示されるようになります。

ということで、今回はGoに関する内容ができなかったので、次回(今日、これから)に持ち越しとなります。


2014年10月26日日曜日

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

Golang Cafe #51を開催しました。今回は結城浩さんの書籍「増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編」のThread-Per-MessageパターンをGoで書くとどうなるか?というお題に挑戦しました。

Thread-Per-Messageパターンがどういうものかというと、「これやっといてね」とメインスレッドが要求を出します。この要求ごとにスレッドが生成され、ワーカースレッドがそれぞれを処理して終了するというものです。

今回はワーカスレッドの代わりに、Goroutineを生成して、終了をChannelで待つという、以前と余り変わらないコードになりました。(Javaの場合は、ワーカースレッドが動いているとプロセスが終了しないが、Goの場合はmain()が終了するとプロセスが終了してしまうので、終了待ちをする必要がある)
作成したのは以下のコードです。結局、Javaを力づくで翻訳した以前のコードとあまりかわらない結果になってしまいました。

問題点は、「Goroutineの終了」をどうやって待つか。と言うところが、今回のポイントになりました。実際のところは、Channelを戻り値で受け取り、for文で全てを受信待ちする(今回のパターン)か、selectを使った待ち方をすることになると思いますが、今回のように全てが終わったらその時点で終了。なら、for文で良いのかな?と考えてたりします。

ちゃんとした(正規のサービスで使う)プログラムの場合は、タイムアウトとか、close()させることもあると思いますからselect文を使うパターンの方が多いのかもしれません。

その他に、私も初めて気がついたのですが、syncパッケージにtype Poolというのが存在していました。そこで少し試しにコードを書いてみました。
sync.Poolは、複数のGoroutineからアクセスされても安全に取得できるように作られていて、GCの影響が少なくなるようになっているようです。
(確かにソースコードを見ると、unsafeが使われているようなので、GCの影響が少なくなるのかも?)

実際にGet()してみたところ、なんとなくですが、順番の保証はされていないような感じがします。(runtime.GOMAXPROCS()を呼びださなくても、順番が正しく動いていない気もする…)

ですが、順番が気にならないのであれば、sync.Poolを使うほうが排他制御を考えなくても良い分使いやすいかもしれません。(グローバル変数を同期して…。的なコードを書かなくても良くなる。ただし、それが悪いとは言っていませんのでご注意を。)

次回、(今日)はisuconの過去問題に挑戦してみます。私はAmazonのクラウド環境を使ったことがないので、そこからかな…。

2014年10月22日水曜日

「Javaプログラマーなら習得しておきたい Java SE 8 実践プログラミング」を読みました。

Blogを書くのが遅くなってしまいましたが、「Javaプログラマーなら習得しておきたい Java SE 8 実践プログラミング」(http://www.amazon.co.jp/dp/4844336673)を読みました。

目次は以下の構成です。

  • 第1章 ラムダ式とは
  • 第2章 ストリームAPIの使い方
  • 第3章 ラムダ式を使ったプログラミング
  • 第4章 JavaFXによるGUIプログラミング
  • 第5章 日付と時刻の新たなAPI
  • 第6章 並行処理の機能強化
  • 第7章 Nashorn JavaScriptエンジンの活用
  • 第8章 その他のJava 8機能を理解する
  • 第9章 Java 7の機能を復習する
私はJava 5が出たあたりで、Javaをほとんど書かなくなってから、AndroidのプログラミングでJava 6のコードを書いているという状態でした。従って、Java 7の内容とか、Java 8の事は殆どわかりません。(以前、Java 8のハンズオンイベントに参加したので、Stream APIとラムダ式は教えて頂いたことがある。)

実は、今回縁あってImpress Japanさんから献本を頂きまして、本書を読むことができました。ありがとうございました。書籍を読む時間が取りづらいのと、貸してほしいとお願いされたこともあって、私は5章まで読んで、以降は流し読みになっていますが、私の印象を書いておきたいと思います。

読む前の印象としては、柴田さんの翻訳本の文章は「日本人には読みづらい」という印象がありました。Goフレーズブックとかが、わりと頭が痛くなる文章だった気がします。
ですが、本書に関しては、わかりやすい文章になっていると思います。

しかし、コード例や、説明がJava 6、Java 7の書き方をしっかり理解していないと、内容を理解するのが難しいと感じました。従って、Java 7の内容がわかっていないのであれば、一度9章を読んでからの方が良いのかもしれません。
(初心者の方は、恐らく途中で挫折してしまうと思いますので、最初の書籍に選択するのはおすすめしません)

ラムダ式の所は、型の記述を省略できるようになっているのですが、引数の型が見てわかるようであれば良いのですが、書籍の例のラムダ式のコードを見てもすぐに型が分からないこともあったので、ある程度、Javaのクラスの事が分かっている方がいいかもしれません。(もしくは、ドキュメントを見ながら読み進める必要があるかもしれません)

本書には(私はまだ取り組んでいませんが)練習問題が用意されていて、練習問題に取り組むことで、理解を深めることができるようになっています。ですから、よくわからなかった所は、練習問題でもう一度、内容を整理して理解するということが可能になっています。

書籍は260ページ程度で、比較的薄い本ですから読み終わるまでに時間はかからないと思います。

今のところ、Java 8の内容全体を見渡せる書籍は本書のみだと思いますので、全体を見渡したい方はお手に取って見てください。

2014年10月13日月曜日

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

Golang Cafe #50を開催しました。今回は、開催地を東京のGoogleオフィスに設定して開催をしました。

今回はGolang Cafe #50での内容ではなく、準備段階などの話に重点をおこうと思います。
Golang Cafe #50を開催するにあたって、Golang Cafe #30の開催時から、+Yoshifumi YAMAGUCHIさんと連絡を取って、「Golang Cafeの開催が50回になったら、オフィスを貸して欲しい+α」とお願いをしました。
すると、簡単にOKが出たので、+Ryuji Iwataさんと、+Takanobu Haginoさんと私の3人でGoogleのオフィスでGolang Cafeをしようという計画が開始されました。

この段階で、他にもGolang Cafeに参加して頂いた方はいらっしゃいましたが、この時点で30回も続くと思っていなかったので、少なくとも、25回以上は参加しているであろう、2人に絞りました。(この時点で他に10回を超える方はいなかった)

ということで、そこから開催を重ねていったわけですが、このGolang Cafe #50のテーマとして、「私のネタに付き合って頂いた方へのお返し」というのを(勝手に、誰にも言わず)掲げて、可能な限り要望に答えられるように進めていったつもりです。2人には今後のGDG中国のGoのコンテンツを支えていただけるようなので(笑)非常に感謝しております。

次に、東京での開催ということで、正直最初の計画段階ではネタで募集して3人で適当にオフィスでやろうか。と話をしていたと思うのですが、だんだんと希望は膨らんでしまって、「東京のGopherと交流を図ろう」ということになりました。
しかし、「規模が大きいものはGoConがある」ので、規模は大きくしない。というもので。
ただ、普段通り募集をかけると、恐らく一瞬で満員御礼+多数のキャンセルによる悲劇が待っているだろうというのが、簡単に想像できたので、Golang Cafe #50に関しては、「非公開+技術者のつながり」で募集をかけようということになりました。
また、西日本のGopherは、今回は私がお誘いするつもりがありませんでした。(理由は交通費の問題と、西日本在住であればすぐに会えるので東京に来ていただく必要がなかった。敢えてお呼びしませんでしたが、悪意はありません。)が、+Yasutaka Kawamotoさんだけは、特別に、+Ryuji Iwataさんの強い要望があったので、(Iwataさんは、なぜか自分から呼ばなかった)私からお誘いしました。
昔、少しだけやっていた、Golang Office HourというHangoutのイベントのことなど、覚えて頂いたようで、ちょっとうれしかったです。+Takuya UedaさんもGolang Office Hourのことを覚えていて、「戦友」だと思いました。
東京のGo言語を使っている方と直接連絡が取れる方というのが非常に少なかったので、こればかりは、+Yoshifumi YAMAGUCHIさんに頼ろうということで、告知等をお願いしました。
そこで、よく考えると、東京にはGDG中国のスタッフ+Shingo Ishimuraさんがいるということに気がついたので、彼を巻き込み、総勢18名の参加者になりました。

後は、直前に風邪をひいたりして、活動がしっかりできませんでしたが、なんとか本番にこぎつけた。という流れです。
本当に、東京でのサポートをして頂いた +Yoshifumi YAMAGUCHIさん、+Shingo Ishimuraさんには助けられました。ありがとうございました。

そして、無茶ぶりにもかかわらず参加していただいた、参加者のみなさんもありがとうございました。いい勉強になりました。楽しかった!

本番のことにも少し触れると、「Golang Cafeの主催者はTakashi Yokoyamaさんです!」と言いながら、自分が主催者であるかのように、突撃してGolang Cafe #50の時に、「Golang Cafeとは」という説明をし始めたり、Rob Pike氏に人の名前を入れてメールを送り、「何かメッセージをくれ」と言って、メッセージを頂いたりと暴れまくってくれた+Ryuji Iwataさんは非常に楽しそうでした。(普段は、私がGoDEとして持ち上げているのでプラスマイナスゼロですかね)セッションを2つもやった挙句に、本番のルール説明は私に投げるという、新しい勉強会のスタイルを教えてくれました(笑)

最終的に2人には満足して頂いたかどうかはわかりませんが、非常に楽しい1日でした。
100%の要望に答えることは不可能だと「再」認識したので、お2人の反応に期待することにします。

Golang Cafeという「毎週みっちり」というのを1年間続けてみた結果ですが、3人はGolangのことは大体わかるようになったのかな?と感じています。ですが、40回台には、テーマ設定が難しい時もありました。(大体見ても、新発見することが少なくなってしまう)それは、成長したからなのでしょうが、連続の開催回数で理想的なのは30回ぐらいまでなのかな?と個人的に思っています。

それから、最初は「個人的にコードを書く時間」という設定で開催をした(zusaarの募集はネタ)のですが、結局それが許される環境には、現時点ではなかったようで、こんなに大きなものになってしまったというのは驚きがあったのと、誤算だったのとでいろいろ発見がありました。それで、Go言語というものが広まるようになるのなら、「まあいいや」ということかなとも思います。

「Golang Cafeの今後」についても少しずつ考えていますので、また次回の#51で話をしようかと思っています。

次回のGolang Cafe #51ですが、台風19号の影響により危険だと判断しましたので、来週(10/19)に順延することにしました。zusaarは満員御礼なのですが、キャンセルをしっかり行っておいて下さい。

2014年9月27日土曜日

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

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

今回は、Gunosy.go#10の発表資料が公開されましたので、資料を読み進めました。

読んだ資料は@y_matsuwitterさんの「Go言語におけるテストの基本」と@daimatzさんの「Dependency Injectionからモックライブラリまで」の2つです。

テストの基本についての大体の内容は、Golang Cafeでも触ってきたものだったので、参加者全員が知っているものでした。特徴として、テストコードに与える引数と、期待する戻り値を書いておいて比較するというサンプルコードが見受けられましたが、標準パッケージでも(特にmathあたり)そのような構成になっています。

ここで、話が出たのは、「どこまでテストをするか?」という話。これまでも何度も出てきていることなのですが、その辺を議論し始めるとGoの話ではなく、開発手法の話になってしまうので難しいところです。
それと、「テストを書きながら作る」か「開発した後で作る」かという話もありました。
それ以外にも「TDDする」というようなことも。
後でテストコードを見ることで、仕様や、プログラマの考えていたことがわかるようなテストを書かなくてはいけないということも話しました。

個人的には、「後でデグレを起こさないようにする」ということに主軸を置いているので、境界値のテストを主にやっておけば良いのかな?と考えていたりします。
全てのコードを通すようなテストを書いておくのは良いと思うのですが、
例えば、fmt.Printf()が失敗した後のケース(昔、そういう仕事をしたもので…)のテストが要るか?と言われると、その「PCが壊れてしまっている」状況で何ができるか?を考えたら、そんなに重要とは思えないので、panic()が書かれている事をコードレビューしておけば良いと思われます。

(こういうのを書いてしまうと、炎上すると困るのでこの程度に…)

Dependensy Injectionの方に入ると、やっぱり「Generics欲しい」という話がありました。私はそこまでGenericsを使いこなしていないので、便利さに気がつかないのですが、Javaや、C#をやっている人にはないと辛いようです。

資料の中身としては、通信が必要だったりするアプリケーションなどにはモックを作って擬似的なテストを行わなければいけない時に遭遇する。それをするためにはDIを使って、テストの時と、本番の時で挙動を変えられるようにしておくと便利ということ。
それをGoでやるにはどうするか。ということで、メソッド引数、オブジェクトを渡す、インターフェイスを引数で。という例が紹介されたようです。

私ももう少しこういう話題について勉強しておかないといけないのかな。と思った回でした。

次回は昔やった、結城浩さんの「Java言語によるデザインパターン入門(マルチスレッド編)」のGoに置き換えるというのを再開する予定です。

個人的には開発したいものがあるんだけど今のGolang Cafeでやるのは難しそう…かな。

2014年9月21日日曜日

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

Golang Cafe #47を開催しました。前回はかなり脱線してしまったので、blogは省略しました。今回は、GoでWebsocketをさわってみるという内容で、go.netのwebsocketを使ってみました。

go.net/websocketのインストールは、以下のコマンドで行います。

$ go get code.google.com/p/go.net/websocket

サンプルコードはgithubにpushしていますので、そちらをごらん下さい。
使い方は非常に簡単で、単純な折り返しのWebsocketならすぐに作れるようになっています。

package main

import (
 "io"
 "net/http"

 "code.google.com/p/go.net/websocket"
)

func echoHandler(ws *websocket.Conn) {
 io.Copy(ws, ws)
}

func main() {
 http.Handle("/echo", websocket.Handler(echoHandler))
 http.Handle("/", http.FileServer(http.Dir("./gdgchugoku_html5_business/html/011")))
 err := http.ListenAndServe(":8080", nil)
 if err != nil {
  panic("ListenAndServe: " + err.Error())
 }
}

githubにも同じものが上がっていますが、転載しました。
Websocketのハンドラ登録は、標準パッケージのhttp.Handle()を使って登録します。
指定するHandlerのオブジェクトでwebsocketパッケージの型を指定するようになっています。

折り返しするだけであれば、io.Copy()で引数のWebsocketのオブジェクトにコピーするだけでいいようになっています。
送信用と受信用の引数があるかと思ったのですが、Websocketの場合はまとまっているようです。

当日、見つけたポイントとしては、Websocketのオブジェクトをずっと使いたい場合は、Handlerの関数を抜けてはいけないということでした。関数を抜けるとsocketがcloseされるので、for {}で無限ループさせる必要があります。

ローカルでのテストしか行っていませんが、レスポンスも早く、サーバ側からの通知などにも利用できるのでWebsocket自体の仕様が固まって、何かに使えればいいなと思いました。

次回は、gunosy.goの資料が公開されているようなので、その資料を読みます。

2014年9月7日日曜日

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

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

今回も、3人での開催になりました。

内容は、急にqiitaに投稿された記事が気になったので、3人で読み進めてみました。
タイトルが「Goでxxxのポインタを取っているプログラムはだいたい全部間違っている」という、結構攻めた感じのタイトルだったので、食いついてしまいました。

内容としては、ポインタを使うのは良いが「自分が何をしているのか理解していない」のであれば、ポインタを使う意味がないということでした。
少し補足をすると、文字列、interface、channel、Map、sliceは「元からポインタ」なので、ポインタを使うと、「ポインタのポインタ」になってしまって、「直接参照すればいいのに何してるの?」ということになってしまう。ということです。

例えば、Mapだと、 +Takanobu Haginoさんのサンプルコードで確認すると、Mapは引数にポインタを渡さなくても、呼び出し先でMapに値を追加することができ、当然、呼び出し元でも追加されたものは反映されます。(=元からポインタということ)

fmt.Println()で書きだしてみると、channelもアドレスが出力されるのでやっぱりポインタだということがわかります。

従って、ポインタを使う時というのがどういう意図があるのかを明確にして使いましょう。ということでした。

次に、@lestrratさんの資料を読みました。
ここで議論になったのが、「intのバイト数が変わる」ということについて。

昔は、intという型はなく、int8、int16、int32、int64とビット数をつけた型だけがありました。(当然、byteもない。昔はint8と宣言していたけど、いつの間にかbyteを使うようになってしまった。これは大きさが変わらないので大丈夫。)

実際、intは”same size as uint"ということで、(個人的にはint32のaliasだと思っていたけど)uintと同じサイズの整数型という定義になります。
そこで、uintのサイズは何かというと、32bit or 64bitなので、goのコンパイラのビルド時に決まる。ということでしょうね。
(C言語のintと変わらず、どちらになるかわからないということ)

したがって、intのサイズが変わることでハマるよ。ということですから、明確にサイズが影響するなら、int32やint64の変数の型を使うようにするべきだろう。という結論になりました。(と私は理解している)

最後に、 +Takanobu Haginoさんのtextream解析ツールのソースコードを読みました。
非常にシンプルだったので、特に何か言わなければならないというものはなかったように思います。
構成としては、バックエンドでサイトの情報を取得して、フロントはgorillaを使ったWebサーバという構成で作られています。
いろんな便利なライブラリも使われていて、「実戦向き」のプログラムで非常に楽しく読ませていただきました。

最近、qiitaにGoogle Apps Scriptの記事を2個書いてましたが、Goに興味がないわけではなく、必要になった要求を簡単に満たせるのがGASだったということで、要求を満たしやすい言語を選ぶのがいいんだろうと思ったりしています。

次回(後2時間後)は、また最近話題になった記事とかソースコードレビューとか、何か作る時間にしたいと思います。