2016/03/29


go-github という、Google が開発している GitHub API ライブラリがあるのですが、今回 filosottile さんがたった4行のコードで実行速度を4倍にするという pull-request を書きました。

いったいどういう事かというと、golang の json.Decoder を使って http.Response.Body から JSON を読み取ると最後の改行(EOF)が読み込まれずに残ってしまい、レスポンスを完全に読み切らないまま http.Response.Body.Close() が呼ばれてしまう。これはこれで別に問題のあるコードではないのですが、継続してリクエストを送る場合にレスポンスを完全に読み切っていなかった事でクライアントは物理切断してしまい TLS 接続が再利用されなくなります。この TLS 接続を再利用する為には残りのたった1バイトを読み捨ててあげる必要がある。そこで

defer func() {
    // Drain and close the body to let the Transport reuse the connection
    io.Copy(ioutil.Discard, resp.Body)
    resp.Body.Close()
}()

というコードになったという事です。個人的にはこれは golang 本体がやるべき仕事な気もするのでオススメはしませんし、今後 golang に何かしらの対応が入るのかもしれませんが、今すぐ高速な HTTP 通信が必要という方は試してみるのも良いかもしれません。

ちなみにこの件、Content-Length 分読み取って json.Unmarshal していれば発生しないはずですが json.Decoder のメモリを極力使わないというメリットが使えなくなるというのもあり一長一短ですね。

Posted at by



2016/03/28


ちょっとした昔話を一つ。

vimで方向キーがABCDを入力してしまう問題の解決 - Qiita

ubuntuでちょっとした設定ファイルを書き換える際にはvimを使っているのだけれど,方向キーでのカーソル入力が何か拍子にABCDと入力になってしまうことが度々あり不便なので原因を調べてみた。 ***...

http://qiita.com/blue_camel/items/e2bd59a3b33acd5edfd0
Vimで方向キー入力時にABCDが記述されるエラー対処 | vdeep

カーソル移動が「h,j,k,l」だとわかっていても、つい押してしまう「方向キー」。するとABCDと訳のわからない入力が。。

http://vdeep.net/vim-abcd

もう少し詳細を知っておくと、もし同じ様な現象に遭遇した時に解決が早くなるかもしれませんね。まずなぜ ABCD が挿入されてしまうのか。端末 vt100 ではカーソルの移動(↑↓←→)はそれぞれ以下のコントロールコードが割り当てられています。

キー コントロールコード
^[[A または ^[OA
^[[B または ^[OB
^[[C または ^[OC
^[[D または ^[OD

ここでの ^[\x1B つまりエスケープです。近代的な端末はこれらを解釈し、画面上の描画位置を期待した通りに移動してくれます。また近代的なプログラムであればこれらのキーシーケンスは一度に解釈されて正しくカーソルキーと判別されます。しかし大昔に作られた vi はこれらの先頭に付いている ESC に反応してインサートモードを抜ける動作になっていました。この結果、↑キーであれば ESC が押されてノーマルモードに戻り O が押されて1行上でインサートモードが開始され、A が押されて挿入される、という動作が行われます。

vi もその後進化し termcap というライブラリを使う様になりました。上記のキーシーケンスは一度に解釈されて正しくカーソルキーと判別される様になりました。しかし vi は互換性を重視するテキストエディタです。デフォルトでは互換モードで動作する為、きちんとこの動作を行う様になっています。オプション nocompatible を設定するだけで現象が直るのはこの為です。ちなみにまだこれらの端末技術が進んでいなかった頃(といってもそれほそお爺さんではありませんが)、僕たちは以下の様なワークアラウンドでカーソルキーを疑似していました。

:map! ^[OA ^[ka
:map! ^[OB ^[ja
:map! ^[OC ^[la
:map! ^[OD ^[ha

^[CTRL-VCTRL-[ で入力します。

カーソルキーが送られてきたら vi の map ですぐさま ESC を判別せずに ESC でノーマルモードに戻り、hjkl で移動し、a で再度インサートモードに戻っていたのです。もちろんこれを設定すると単独で ESC をタイプした時にタイムアウトが発生するまでキーが解釈されないので反応が悪くなります。

そして次第にこういったワークアラウンドは使わず hjkl で移動する様になりました。良くも悪くもカーソルキーを使わず操作する為のギプスだったのですね。

Posted at by




golangでIOへのテストを行う | おおたの物置

まとめ fmt.Print等にちゃんと出力されるかテストしたい 結論としては直接は無理 io.Writerを利用するように変えることで簡単にテスト可能 渡されたio.Writerに書き込むようにする ...

http://ota42y.com/blog/2015/04/01/go-io-test/

golang には Example Test という機能があり、テスト関数名に Example のプレフィックスを付ける事で実行結果として出力される標準出力のテストを行う事が出来ます。

期待する結果はこの関数の中にコメントとして書くことが出来ます。

go-pipeline/example_test.go at master - mattn/go-pipeline-· GitHub
https://github.com/mattn/go-pipeline/blob/master/example_test.go

このまま go test として使えるので、CI にもそもままのコードが使えます。

ところで golang のテストで稀にハマるのが「map のイテレートが順不同である」という件。ある map を加工した結果がある期待値と同じかどうかを確認する為に reflect を使うとか面倒ですよね。そこで go1.7 には Unordered Output in Example という機能が入る予定です。

testing: support unordered output in Examples. · Issue #10149 · golang/go · GitHub

Other use cases are like the one I am specifically working on now. A client I work on makes calls to...

https://github.com/golang/go/issues/10149

都合上、issue がまだ閉じられていませんが、コードはマージ済みなので tip で使う事が出来ます。

func ExampleShuffle() {
    x := []int{12345}
    shuffle.ShuffleInt(x)
    for index, value := range x {
        fmt.Printf("index[%d] = %d\n", index, value)
    }

    // Unordered output:
    // 4
    // 2
    // 5
    // 1
    // 3
}

Output の代わりに Unordered output を指定する事で、結果の順が不同であっても OK となります。気軽に map の検査が行える様になりました。

Posted at by