1. 程式人生 > 實用技巧 >go筆記-理解幾種Context

go筆記-理解幾種Context

WithCancel

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)

WithCancel返回一個新的parent拷貝Done channel。當呼叫返回的cancel函式parent的上下文的Done channel被關閉時(以先發生的為準),將關閉返回的上下文的Done channel。
取消此上下文將釋放與其關聯的資源,因此在此上下文中執行的操作完成後,程式碼應立即呼叫cancel。

示例
此示例演示了使用可取消的context來防止goroutine洩漏。 在示例函式結束時,由gen方法啟動的goroutine將返回而不會洩漏。

package main
import (
	"context"
	"fmt"
)
func main() {
	// gen generates integers in a separate goroutine and
	// sends them to the returned channel.
	// The callers of gen need to cancel the context once
	// they are done consuming generated integers not to leak
	// the internal goroutine started by gen.
	gen := func(ctx context.Context) <-chan int {
		dst := make(chan int)
		n := 1
		go func() {
			for {
				select {
				case <-ctx.Done():
					return // returning not to leak the goroutine
				case dst <- n:
					n++
				}
			}
		}()
		return dst
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel() // cancel when we are finished consuming integers

	for n := range gen(ctx) {
		fmt.Println(n)
		if n == 5 {
			break
		}
	}
}

WithDeadline

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
WithTimeout內部呼叫了WithDeadline,返回結果為WithDeadline(parent, time.Now().Add(timeout)).
取消此上下文將釋放與之關聯的資源,因此在此上下文中執行的操作完成後,程式碼應立即呼叫cancel:
示例
此示例傳遞了帶有超時的上下文,以告知阻塞函式在超時結束後應放棄任務。

package main

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

const shortDuration = 1 * time.Millisecond

func main() {
	// Pass a context with a timeout to tell a blocking function that it
	// should abandon its work after the timeout elapses.
	ctx, cancel := context.WithTimeout(context.Background(), shortDuration)
	defer cancel()

	select {
	case <-time.After(1 * time.Second):
		fmt.Println("overslept")
	case <-ctx.Done():
		fmt.Println(ctx.Err()) // prints "context deadline exceeded"
	}

}
// 執行後1ms立刻輸出 "context deadline exceeded"

示例2

package main
import (
  "context"
  "fmt"
  "time"
)
const shortDuration = 500 * time.Millisecond

func work(ctx context.Context, doneChan chan struct{}) {
  defer func() {
    fmt.Println("work end")
  }() 
  fmt.Println("work start")
  time.Sleep(100 * time.Second)
  fmt.Println("work finished")
  doneChan <- struct{}{}
}
func main() {
  doneChan := make(chan struct{}, 1)
  dlCtx, cancel := context.WithTimeout(context.Background(), shortDuration)
  defer func() {
    cancel()
    fmt.Println("cancel")                                                                                                                                                                                                             
  }() 
  fmt.Println("main start")

  go work(dlCtx, doneChan)
  select{
  case <- dlCtx.Done():
    fmt.Println("timeout")
  case <- doneChan:
    fmt.Println("finish")
  }
  fmt.Println("main end")
}

輸出:
main start
work start
timeout
main end
cancel

WithTimeout
WithValue