blog

Golang-context

役割1、Webプログラミングは、リクエストが複数のgoroutine 2、タイムアウト制御、制御非同期リクエストタイムアウト3、コンテキスト制御の間のデータの相互作用に対応し、リクエストの流れを追跡す...

Dec 8, 2020 · 5 min. read
シェア

は英語の -ity、-ism、-ization に対応します。

1、Webプログラミング、要求は、複数のゴルーチン間のデータの相互作用に対応します。

2、タイムアウト制御、制御非同期リクエストタイムアウト

3、コンテキスト制御、リクエストの流れを追跡

Golangのコンテキスト

Golangのコンテキスト

// コンテキスト情報を要求する
context
// 役割:複数のgouroutineとリクエストドメインのデータ、キャンセルシグナル、デッドライン、その他の関連する操作の間で、1つのリクエストの処理を単純化するために使われる。
type Context interface { 
 // 締め切りを設定する
 // deadline : その時点で、コンテキストは自動的にキャンセルリクエストを開始する。
 // ok == false は期限が設定されていないことを意味し、キャンセルする必要がある場合はキャンセル関数を呼び出す必要がある。
 Deadline() (deadline time.Time, ok bool) 
 // struct型の読み取り専用チャンを返す{},
 // goroutineの中で、メソッドが返すchanを読むことができれば、それは親コンテキストがキャンセル要求を開始したことを意味し、Done()メソッドを通してこのシグナルを受け取ったら、クリーンアップを行う必要がある。
 // その後、ゴルーチンを終了してリソースを解放し、Err()メソッドがコンテキストがキャンセルされた理由を示すエラーを返す。
 Done() <-chan struct{} 
 
 //どのようなコンテキストがキャンセルされたので、エラーのキャンセルの原因を返す
 Err() error 
 //Contextにバインドされた値を取得するのは値のペアで、キーを通して対応する値を取得できる。
 Value(key interface{}) interface{} 
}
Context 
// 親Contextをパラメータとして渡し、子ContextとContextをキャンセルするcancel関数を返す。
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
// WithCannelと同じように、もう1つ期限パラメータを渡す。つまり、この時点でContextは自動的にキャンセルされる。
func WithDeadline(parent Context, deadline time.Time)(Context,CancelFunc)
// WithDeadlineも基本的には同じで、自動キャンセルされた後どれくらいの時間が経てば
func WithTimeout(parent Context,timeout time.Duration)(Context,CancelFunc)
// データを値のペアにバインドするContextを生成することで、バインドされたデータをContextを通して渡すことができる。.Valueメソッドへのアクセス
func WithValue(parent Context, key ,val interface{}) Context

Golangのコンテキスト

// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
	return
}
func (*emptyCtx) Done() <-chan struct{} {
	return nil
}
func (*emptyCtx) Err() error {
	return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
	return nil
}
func (e *emptyCtx) String() string {
	switch e {
	case background:
		return "context.Background"
	case todo:
		return "context.TODO"
	}
	return "unknown empty Context"
}

Golangのコンテキスト

// A valueCtx carries a key-value pair. It implements Value for that key and
// delegates all other calls to the embedded Context.
type valueCtx struct {
	Context
	key, val interface{}
}

Golangのコンテキスト

// A cancelCtx can be canceled. When canceled, it also cancels any children
// that implement canceler.
type cancelCtx struct {
	Context
	mu sync.Mutex // protects following fields
	done chan struct{} // created lazily, closed by first cancel call
	children map[canceler]struct{} // set to nil by the first cancel call
	err error // set to non-nil by the first cancel call
}

Golangのコンテキスト

// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
// implement Done and Err. It implements cancel by stopping its timer then
// delegating to cancelCtx.cancel.
type timerCtx struct {
	cancelCtx
	timer *time.Timer // Under cancelCtx.mu.
	deadline time.Time
}

Golangのコンテキスト

Golangのコンテキスト

// with_value
//  
func with_value() {
	// ルートコンテキストを宣言する
	ctx, cancel := context.WithCancel(context.Background())
	valueCtx := context.WithValue(ctx, "key", "add value")
	go watch(valueCtx)
	time.Sleep(5 * time.Second)
	cancel()
	time.Sleep(1 * time.Second)
}
func watch(ctx context.Context) {
	fmt.Println("go watch")
	for {
		select {
		case <-ctx.Done():
			// コンテキストはキャンセルされる
			fmt.Println(ctx.Value("key"), "is cancel")
			time.Sleep(1 * time.Second)
		default:
			fmt.Println(ctx.Value("key"), "int goroutine")
			time.Sleep(1 * time.Second)
		}
	}
}

Golangのコンテキスト

// with_deadtime
// 締め切り
func with_deadtime() {
	dt := time.Now().Add(3 * time.Second)
	ctx, cancel := context.WithDeadline(context.Background(), dt)
	defer cancel()
	go func(ctx context.Context) {
		for {
			select {
			case <-time.After(2 * time.Second):
				fmt.Println("期限に達した")
			case <-ctx.Done():
				fmt.Println("コンテキストキャンセル")
				return
			}
		}
	}(ctx)
	time.Sleep(5 * time.Second)
}

Golangのコンテキスト


// with_timeout
//  
func with_timeout() {
	ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second)
	defer cancel()
	fmt.Println("with_timeout start")
	var wg sync.WaitGroup
	wg.Add(1)
	go work(ctx, &wg)
	wg.Wait()
	fmt.Println("with_timeout end")
}
func work(ctx context.Context, wg *sync.WaitGroup) error {
	defer wg.Done()
	for i := 0; i < 1000; i++ {
		select {
		case <-time.After(1 * time.Second):
			fmt.Println("Golangのコンテキスト, i)
		case <-ctx.Done():
			fmt.Println("Cancel context", i)
			return ctx.Err()
		}
	}
	return nil
}

、同時リクエストのタイムアウトは、すべてのリクエストをキャンセルします。


func task1() int {
	time.Sleep(3 * time.Second)
	return 1
}
func task2() int {
	time.Sleep(2 * time.Second)
	return 2
}
func task3() int {
	time.Sleep(2 * time.Second)
	return 3
}
// with_url
// あるリクエストがトリガーとなって3つのタスクが同時に完了し、1回のタイムアウトでそれらすべてがキャンセルされる。
// 1Golangのコンテキスト
// 2Golangのコンテキスト
func with_url() {
	var res, sum int
	// Golangのコンテキスト
	sucess := make(chan int)
	// 各タスクの結果を保存する
	resChan := make(chan int, 3)
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()
	// の起動後にすべてのタスクが完了するように同期を使う。
	var wg sync.WaitGroup
	wg.Add(3)
	go func() {
		resChan <- task1()
		wg.Done()
	}()
	go func() {
		resChan <- task2()
		wg.Done()
	}()
	go func() {
		resChan <- task3()
		wg.Done()
	}()
	go func() {
		for {
			select {
			case res = <-resChan:
				sum += res
				fmt.Println("add", res)
			case <-sucess:
				fmt.Println("全てのタスクが完了した後の結果", sum)
				// wg.Done()
				return
			case <-ctx.Done():
				fmt.Println("タイムアウト後の結果 ", sum)
				// wg.Done()
				return
			}
		}
	}()
	wg.Wait()
	// タスクが完了したことを示す
	sucess <- 1
}
func main() {
	with_url()
}
Read next

仮想マシンで初めて Linux システムを起動する。

1、Linux を初めて起動した後、初期化設定を入力し、ライセンスに同意して、"End Configuration "をクリックします。 2、次のインターフェイスに入ると、初めてログインしたユーザと未登録のユーザが表示されます。デフォルトでは、Linux のインストール時に作成したユーザが表示されます。 3、次のインターフェイスに入ると、初めてログインしたユーザと未登録のユーザが表示されます。

Dec 8, 2020 · 3 min read