概要
最初にプログラム作ったときのサンプルって大抵HelloWorldですよね。
その言語のプログラムの基本構造、出力の方法を学べる基本のプログラムだと思いますが、たまにこれで遊ぶと面白いし勉強にもなります。
てことで、以下サンプルです。
同期版
// Package helloworld -- Go言語での Hello World プログラムが配置されているパッケージです。 package helloworld import "fmt" // Sync -- GO言語でのHelloWorldサンプル (同期版) func Sync() error { // Golang には、 ビルドイン関数の println と // fmt.Println という 名前の似ている2つの関数があるが // 基本的に、どのサンプルも fmt.Println を利用している。 // // 理由は、Golang のドキュメントに以下のように記載されているから。 // https://golang.org/builtin/#println // https://qiita.com/taji-taji/items/79a49c0ee329d0b9c065 for i := 0; i < 10; i++ { fmt.Printf("[%02d]\tHello World\n", i+1) } return nil }
実行すると以下のようになります。
gitpod /workspace/try-golang $ make run go run github.com/devlights/try-golang/cmd/trygolang -onetime -example "" ENTER EXAMPLE NAME: helloworld_sync [Name] "helloworld_sync" [01] Hello World [02] Hello World [03] Hello World [04] Hello World [05] Hello World [06] Hello World [07] Hello World [08] Hello World [09] Hello World [10] Hello World [Elapsed] 19.398µs
非同期版
package helloworld import ( "context" "fmt" "math/rand" "time" "github.com/devlights/gomy/ctxs" ) // Async -- HelloWorld 非同期版 func Async() error { // main contexts var ( rootCtx = context.Background() mainCtx, mainCxl = context.WithCancel(rootCtx) ) defer mainCxl() // proc context var ( timeLimit = 100 * time.Millisecond procCtx, procCxl = context.WithTimeout(mainCtx, timeLimit) ) defer procCxl() // start tasks var tasks []context.Context for i := 0; i < 10; i++ { tasks = append(tasks, func(pCtx context.Context, no, delay int) context.Context { var ( ctx, cxl = context.WithCancel(pCtx) ) go func() { defer cxl() select { case <-ctx.Done(): fmt.Printf("[%02d]\tTime out\t(%02d msec delay)\n", no, delay) case <-time.After(time.Duration(delay) * time.Millisecond): fmt.Printf("[%02d]\tHello World\t(%02d msec delay)\n", no, delay) } }() return ctx }(procCtx, i+1, rand.Intn(100))) } // wait until all tasks are completed <-ctxs.WhenAll(procCtx, tasks...).Done() return nil }
実行すると以下のようになります。
gitpod /workspace/try-golang $ make run go run github.com/devlights/try-golang/cmd/trygolang -onetime -example "" ENTER EXAMPLE NAME: helloworld_async [Name] "helloworld_async" [03] Hello World (02 msec delay) [08] Hello World (02 msec delay) [04] Hello World (13 msec delay) [09] Hello World (48 msec delay) [06] Hello World (49 msec delay) [02] Hello World (59 msec delay) [10] Hello World (74 msec delay) [07] Hello World (75 msec delay) [05] Hello World (82 msec delay) [01] Hello World (83 msec delay) [Elapsed] 84.097568ms
同期と非同期を混ぜ混ぜ
package helloworld import ( "context" "time" "github.com/devlights/gomy/ctxs" "github.com/devlights/gomy/output" ) // Mixed -- 同期と非同期の両方で同じことをするサンプル func Mixed() error { // main contexts var ( rootCtx = context.Background() mainCtx, mainCxl = context.WithCancel(rootCtx) ) defer mainCxl() // proc context var ( procCtx, procCxl = context.WithTimeout(mainCtx, 1*time.Second) ) defer procCxl() // start tasks var ( syncCtx = sync(procCtx) asyncCtx = async(procCtx) ) // wait until all tasks are completed <-ctxs.WhenAll(procCtx, syncCtx, asyncCtx).Done() return nil } func sync(pCtx context.Context) context.Context { var ( ctx, cxl = context.WithCancel(pCtx) ) go func() { defer cxl() for v := range items() { v := v <-exec(ctx, v+1, "sync ").Done() } }() return ctx } func async(pCtx context.Context) context.Context { var ( ctx, cxl = context.WithCancel(pCtx) tasks = make([]context.Context, 0) ) for v := range items() { v := v tasks = append(tasks, exec(ctx, v+1, "async")) } go func() { defer cxl() <-ctxs.WhenAll(ctx, tasks...).Done() }() return ctx } func items() <-chan int { var ( ch = make(chan int) ) go func() { defer close(ch) for i := 0; i < 10; i++ { ch <- i } }() return ch } func exec(pCtx context.Context, v int, prefix string) context.Context { var ( ctx, cxl = context.WithCancel(pCtx) ) go func() { defer cxl() select { case <-ctx.Done(): return default: output.Stderrf(prefix, "[%02d] helloworld\n", v) } }() return ctx }
実行すると以下のようになります。
gitpod /workspace/try-golang $ make run go run github.com/devlights/try-golang/cmd/trygolang -onetime -example "" ENTER EXAMPLE NAME: helloworld_mixed [Name] "helloworld_mixed" async [02] helloworld sync [01] helloworld sync [02] helloworld async [01] helloworld sync [03] helloworld sync [04] helloworld sync [05] helloworld sync [06] helloworld sync [07] helloworld sync [08] helloworld async [04] helloworld async [06] helloworld async [05] helloworld sync [09] helloworld async [08] helloworld sync [10] helloworld async [10] helloworld async [07] helloworld async [09] helloworld async [03] helloworld [Elapsed] 548.179µs
syncの表示は逐次的になっていて(1から10まで順に出力)、asyncの表示は非同期となっていますね。
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場