LoginSignup
44
42

More than 5 years have passed since last update.

逆引きgolang

Last updated at Posted at 2014-07-07

随時更新

Goroutine & Channel

goroutineの終了を待つ

(http://jxck.hatenablog.com/entry/20130414/1365960707 が良記事です)

1つのgoroutineを待つだけならchannelを使えばok:

main.go
package main

import "log"

func main() {
  ch := make(chan int)
  go func(ch chan int) {
    // do something

    log.Printf("end of goroutine")
    ch <- 1
  }(ch)
  log.Printf("waiting for goroutine")
  <- ch
  log.Printf("end of main")
}

複数のgoroutineを待つ場合はsync.WaitGroupを使うらしいです:

main.go
package main

import (
  "log"
  "sync"
)

func main() {
  var wg sync.WaitGroup
  for i := 0; i < 3; i++ {
    wg.Add(1) // goroutineの数だけAdd()
    go func(i int) {
      defer wg.Done() // goroutineを抜けたらDone()
      log.Printf("goroutine: %d", i)
    }(i)
  }
  log.Printf("waiting for goroutines")
  wg.Wait() // ここでblockして待つ
  log.Printf("end of main")
}

ちなみに細かいことですが、Done()が呼ばれたそばから終了するので、複数のdeferを呼ぶ場合は、Done()を"最初に"書いておかないと他のdeferが呼ばれる前にプロセスが終了してしまう可能性があります (deferはLIFOで実行されます: http://blog.golang.org/defer-panic-and-recover)

Build

debug / release buildを分ける

build tagを使います。(例えば)env packageにenv_debug.goとenv_release.goをつくって、それぞれにbuild条件を書くと、build tagにmatchするファイルだけがbuildされます。

env/env_debug.go
// +build !release

package env

const DEBUG = true
env/env_release.go
// +build release

package env

const DEBUG = false

このとき、"// +build ..."は1行目に書く必要があって、且つ、1行空行が必要です。で、このpackageをimportして振る舞いを分けます。

main.go
package main

import (
  "github.com/user/app/env"
)

func main() {
  if env.DEBUG {
    // ...
  }
}

debug buildは

$ go build github.com/user/app

で、release buildは

$ go build -a -tags=release github.com/user/app

になります (build tagを変えただけの場合は、正しく全てのライブラリがbuildし直されない可能性があるので、-aが無難です)。

その他

呼び出し元のfuncを取得する

pc, _, _, _ := runtime.Caller(1)
caller_name := runtime.FuncForPC(pc).Name();

で出来ます。DEBUGフラグとかがあれば:

debug.go
import (
  "log"
  "runtime"
  "github.com/user/app/env"
)

func Debug(format string, args ...interface{}) {
  if env.DEBUG {
    pc, _, _, _ := runtime.Caller(1)
    caller_name := runtime.FuncForPC(pc).Name();

    log.Printf(caller_name + ": " + format, args...)
  }
}

で、デバッグログが出力しやすくなる気がします。

packageのprefixを省略する

main.go
package main

import (
  "log"
)

func main() {
  log.Printf("hello")
}

とかの"log."を省略するには

import (
  . "log"
)

とすると

Printf("hello")

と書けます、まめ知識です。同様に、

import (
  foo "log"
)

とすれば

foo.Printf("hello")

でアクセスできます。

See Also, and Reference Sites

44
42
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
44
42