2016/04/05


だいぶ時間が掛かった様ですが、ようやく buildmode=c-archive が Windows でも使える様になりました。

cmd/go: -buildmode=c-archive should work on windows · Issue #13494 · golang/go · GitHub

32-bit is also important to me. I'd like to help. I'm seeing those same link errors when I enable it...

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

まだ buildmode=c-shared (いわゆる dll) はビルド出来ないけど、ひとまずC言語から golang のライブラリをリンクして動かせる様になりました。例えばこんな事が出来ます。

package main

import "C"

import (
    "fmt"
    "github.com/mattn/go-haiku"
)

var (
    q = make(chan string)
)

func init() {
    go func() {
        for {
            fmt.Println(<-q)
        }
    }()
}

//export PrintHello
func PrintHello(p *C.char) {
    q <- C.GoString(p)
}

//export IsHaiku
func IsHaiku(p *C.char) C.int {
    var ret C.int
    if haiku.Match(C.GoString(p), []int{575}) {
        ret = 1
    }
    return ret
}

//export PrintLine
func PrintLine(p *C.char) {
    fmt.Println(C.GoString(p))
}

func main() {
}

この様なソースコード lib.go を用意し以下の手順で lib.a を作ります。

go build -buildmode=c-archive lib.go

そしてC言語からは以下の様に呼び出します。

#include <stdio.h>

int
main(int argc, char* argv[]) {
  extern void PrintHello(char*);
  PrintHello("hello");
  PrintHello("hello");
  PrintHello("hello");
  PrintHello("hello");
  PrintHello("hello");
  Sleep(3000);
  return 0;
}

ビルドは以下の様になります。

gcc -o example.exe example.c lib.a -lws2_32 -lntdll

goroutine と channel を使っているので PrintHello の呼び出しは非同期に画面出力されます。golang では簡単に扱えるけどC言語だと若干手間だなと思える様な処理もリンクするだけで使える様になります。以下は ikawaha さんの kagome を使って俳句を扱えるライブラリ go-haiku をC言語から呼び出しています。

#include <stdio.h>

int
main(int argc, char* argv[]) {
  extern void PrintLine(char*);
  extern int IsHaiku(char*);

  char* s = "古池や蛙飛び込む水の音";

  PrintLine(s);
  if (IsHaiku(s)) {
    PrintLine("それ575じゃん");
  }
  return 0;
}
古池や蛙飛び込む水の音
それ575じゃん

めちゃめちゃ簡単ですね。

プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES) プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
Alan A.A. Donovan, Brian W. Kernighan, 柴田 芳樹
丸善出版 単行本(ソフトカバー) / ¥4,180 (2016年06月20日)
 
発送可能時間:

Posted at by



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 のメモリを極力使わないというメリットが使えなくなるというのもあり一長一短ですね。

Go言語によるWebアプリケーション開発 Go言語によるWebアプリケーション開発
Mat Ryer, 鵜飼 文敏, 牧野 聡
オライリージャパン 大型本 / ¥3,520 (2016年01月22日)
 
発送可能時間:

Posted at by



2016/03/28


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 の検査が行える様になりました。

スターティングGo言語: Go1.6に対応 スターティングGo言語: Go1.6に対応
松尾 愛賀
翔泳社 単行本 / ¥3,278 (2016年04月01日)
 
発送可能時間:

Posted at by