Goのcontextを使ってみる

Go

WithCancel

WithCancel()でキャンセル用のcontextを作成しておき、2秒待ってから、cancel()を実行して処理を中止するように、longRunningTask()に伝えています。

こうすることで、それ以上実施する必要のない処理を止めることができるようになります。

package main

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

// 長時間かかる処理をシミュレートする関数
func longRunningTask(ctx context.Context) {
	select {
	case <-time.After(5 * time.Second):
		// 処理が完了した場合
		fmt.Println("Task completed")
	case <-ctx.Done():
		// キャンセルやタイムアウトが発生した場合
		fmt.Println("Task canceled:", ctx.Err())
	}
}

func main() {
	// キャンセル可能なコンテキストを生成
	ctx, cancel := context.WithCancel(context.Background())

	go longRunningTask(ctx) // 長時間かかる処理を非同期で実行

	// 2秒後にキャンセルを呼び出す
	time.Sleep(2 * time.Second)
	cancel()

	// 処理が完了するか、キャンセルされるまで待つ
	time.Sleep(6 * time.Second)
	fmt.Println("Main function completed")
}

WithTimeout

withTimeout()を使えば、上記の処理をよりシンプルに書くことができます。

3秒後にキャンセルが実行されるcontextを作成して、longRunningTask()に処理を中止するように伝えることが可能です。

package main

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

func longRunningTask(ctx context.Context) {
	select {
	case <-time.After(5 * time.Second):
		// 処理が完了した場合
		fmt.Println("Task completed")
	case <-ctx.Done():
		// キャンセルやタイムアウトが発生した場合
		fmt.Println("Task canceled:", ctx.Err())
	}
}

func main() {
	// タイムアウト付きのコンテキストを生成(3秒後にタイムアウト)
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel() // 3秒後に処理を中止

	go longRunningTask(ctx)

	time.Sleep(6 * time.Second)
	fmt.Println("Main function completed")
}

WithDeadline

WithDeadline()を使うと、指定の時刻までに処理が完了されなければキャンセルすることが可能になります。WithTimeout()が指定時間経過後なのに対して、こちらは指定期日までに、という点が異なっています。

package main

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

func longRunningTask(ctx context.Context) {
	select {
	case <-time.After(5 * time.Second):
		// 処理が完了した場合
		fmt.Println("Task completed")
	case <-ctx.Done():
		// キャンセルやタイムアウトが発生した場合
		fmt.Println("Task canceled:", ctx.Err())
	}
}

func main() {
	// 現在の時刻から3秒後にタイムアウトするコンテキストを生成
	deadline := time.Now().Add(3 * time.Second)
	ctx, cancel := context.WithDeadline(context.Background(), deadline)
	defer cancel()

	go longRunningTask(ctx)

	time.Sleep(6 * time.Second)
	fmt.Println("Main function completed")
}