post Image
Go の Context を学ぶ

Azure SDK for go を使っていると、突然 Context というものが出てきて意味がわからなかったので調べて見た。

公式のリファレンスを読んだのちに

次のブログがとてもわかりやすかった。

ざっとまとめると、Context は、APIのサーバーやクライアントを使うときに、コンテキストを提供してキャンセルや、タイムアウト、値を渡したり出来る仕組み。

Context 構造体の持っている属性や関数に関しては上記のブログに書いてあるので、ここでは書かないけど、何もなし(Background) キャンセル、タイムアウト、値渡しなどの関数が存在する。Context の構造体自体はキャンセルのメソッドは提供しないが、Context はデコレーターの様になっておりラップが可能担っている。上記のブログのサンプルを拡張して見た。

基本的な使い方

go routine などを呼び出す元の方でオブジェクトを生成する。context.Background() は空のコンテキストを生成する。

ctx := context.Background()

これをgo routine を実行時に引き渡す。

    go infiniteLoop(ctx)

go routine の方では、それを受け取る。この例ではループが回るが、キャンセルされたら、Done() が呼ばれるので、メッセージを出力する。

ポイントは、コンテキストオブジェクトは、デコレータの様な使い方をするところ。この例では、渡ってきたのは、空のContextが渡ってきているが、ここで、context.WithCancel(ctx) の様にラップしてキャンセル機能を追加している。

func infiniteLoop(ctx context.Context) {
    innerCtx, cancel := context.WithCancel(ctx)
    defer cancel()
    for {
        fmt.Println("Waiting for time out")

        select {
        case <-innerCtx.Done():
            fmt.Println("Exit now!")
            return
        default:

        }
    }
}

タイムアウトの実装

たとえばタイムアウトを追加したければ、本体側でこんな感じで書けば良い。キャンセルされたらキャンセルの関数が呼ばれる様に defer 関数を使っておく。

    ctx := context.Background()
    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
        defer cancel()

しっかりと 5秒後にキャンセルされ、Done が呼ばれる。

Key/Value 値を設定する

Context はキーバリューも保持できる様になっている。これもデコレータ的な使い方をする。

    ctx := context.Background()
    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    ctx = context.WithValue(ctx, "message", "hi")

go routine 側でこの値を取りたければこんな感じにすると良い。KeyValue の型はinterface {} なので、型変換が必要。

fmt.Println("message:", ctx.Value("message").(string))

コード全体

こちらにコードを置いておいた

全体を載せておく。

package main

import (
    "context"
    "fmt"
    "time"
)

func infiniteLoop(ctx context.Context) {
    innerCtx, cancel := context.WithCancel(ctx)
    defer cancel()
    for {
        fmt.Println("Waiting for time out")
        //time.Sleep(time.Second)
        // If I put sleep in here, fmt.Println doesn't output the "Exit now!"

        select {
        case <-innerCtx.Done():
            fmt.Println("Exit now!")
            fmt.Println("message:", ctx.Value("message").(string))
            return
        default:

        }
    }
}

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    ctx = context.WithValue(ctx, "message", "hi")
    defer cancel()

    go infiniteLoop(ctx)

    select {
    case <-ctx.Done():
        fmt.Println(ctx.Err())
    }
}

次のステップ

Context は理解できたと思うが、上記のサンプルコードには一点わからないことがある。上記のもので、time.Sleep(time.Second) を有効にすると、キャンセル時に、fmt.Println("Exit now!") が実行されない。なんでだろう。


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。