Skip to content

Latest commit

ย 

History

History
570 lines (474 loc) ยท 22.4 KB

context.md

File metadata and controls

570 lines (474 loc) ยท 22.4 KB

context

ๅ…ˆ็ฎ€ๅ•็š„ไบ†่งฃไธ€ไธ‹ๅ‡ ็ง ctx:

  • emptyCtx๏ผŒๆ‰€ๆœ‰ ctx ็ฑปๅž‹็š„ๆ น๏ผŒ็”จ context.TODO()๏ผŒๆˆ– context.Background() ๆฅ็”Ÿๆˆใ€‚
  • valueCtx๏ผŒไธป่ฆๅฐฑๆ˜ฏไธบไบ†ๅœจ ctx ไธญๅตŒๅ…ฅไธŠไธ‹ๆ–‡ๆ•ฐๆฎ๏ผŒไธ€ไธช็ฎ€ๅ•็š„ k ๅ’Œ v ็ป“ๆž„๏ผŒๅŒไธ€ไธช ctx ๅ†…ๅชๆ”ฏๆŒไธ€ๅฏน kv๏ผŒ้œ€่ฆๆ›ดๅคš็š„ kv ็š„่ฏ๏ผŒไผšๅฝขๆˆไธ€ๆฃตๆ ‘ๅฝข็ป“ๆž„ใ€‚
  • cancelCtx๏ผŒ็”จๆฅๅ–ๆถˆ็จ‹ๅบ็š„ๆ‰ง่กŒๆ ‘๏ผŒไธ€่ˆฌ็”จ WithCancel๏ผŒWithTimeout๏ผŒWithDeadline ่ฟ”ๅ›ž็š„ๅ–ๆถˆๅ‡ฝๆ•ฐๆœฌ่ดจไธŠ้ƒฝๆ˜ฏๅฏนๅบ”ไบ† cancelCtxใ€‚
  • timerCtx๏ผŒๅœจ cancelCtx ไธŠๅŒ…ไบ†ไธ€ๅฑ‚๏ผŒๆ”ฏๆŒๅŸบไบŽๆ—ถ้—ด็š„ cancelใ€‚

basic usage

ไฝฟ็”จ emptyCtx ๅˆๅง‹ๅŒ– context

็”จๆฅๅฎž็Žฐ context.TODO() ๅ’Œ context.Background()๏ผŒไธ€่ˆฌๆ˜ฏๆ‰€ๆœ‰ context ๆ ‘็š„ๆ นใ€‚

// 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

var (
	background = new(emptyCtx)
	todo       = new(emptyCtx)
)

todo ๅ’Œ background ไธค่€…ๆœฌ่ดจไธŠๅชๆœ‰ๅๅญ—ๅŒบๅˆซ๏ผŒๅœจๆŒ‰ string ่พ“ๅ‡บ็š„ๆ—ถๅ€™ไผšๆœ‰ๅŒบๅˆซใ€‚

func (e *emptyCtx) String() string {
   switch e {
   case background:
      return "context.Background"
   case todo:
      return "context.TODO"
   }
   return "unknown empty Context"
}

ไฝฟ็”จ valueCtx ๅตŒๅ…ฅๆ•ฐๆฎ

valueCtx ไฝฟ็”จ

package main

import (
	"context"
	"fmt"
)

type orderID int

func main() {
	var x = context.TODO()
	x = context.WithValue(x, orderID(1), "1234")
	x = context.WithValue(x, orderID(2), "2345")
	x = context.WithValue(x, orderID(3), "3456")
	fmt.Println(x.Value(orderID(2)))
}

่ฟ™ๆ ท็š„ไปฃ็ ไผš็”Ÿๆˆไธ‹้ข่ฟ™ๆ ท็š„ๆ ‘๏ผš

           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”            
           โ”‚  emptyCtx  โ”‚            
           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜            
                  โ–ฒ                  
                  โ”‚                  
                  โ”‚                  
                  โ”‚    parent        
                  โ”‚                  
                  โ”‚                  
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚      valueCtx{k: 1, v: 1234}      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                  โ–ฒ                  
                  โ”‚                  
                  โ”‚                  
                  โ”‚    parent        
                  โ”‚                  
                  โ”‚                  
                  โ”‚                  
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚      valueCtx{k: 2, v: 2345}      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                  โ–ฒ                  
                  โ”‚                  
                  โ”‚    parent        
                  โ”‚                  
                  โ”‚                  
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚      valueCtx{k: 3, v: 3456}      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

็ฎ€ๅ•ๆ”นไธ€ไธ‹ไปฃ็ ๏ผŒ่ฎฉ็ป“ๆžœๆ›ดๅƒไธ€ๆฃตๆ ‘๏ผš

package main

import (
	"context"
	"fmt"
)

type orderID int

func main() {
	var x = context.TODO()
	x = context.WithValue(x, orderID(1), "1234")
	x = context.WithValue(x, orderID(2), "2345")

	y := context.WithValue(x, orderID(3), "4567")
	x = context.WithValue(x, orderID(3), "3456")

	fmt.Println(x.Value(orderID(3)))
	fmt.Println(y.Value(orderID(3)))
}

ๅฐฑๆ˜ฏๅƒไธ‹้ข่ฟ™ๆ ท็š„ๅ›พไบ†๏ผš

                          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                       
                          โ”‚  emptyCtx  โ”‚                                       
                          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                       
                                 โ–ฒ                                             
                                 โ”‚                                             
                                 โ”‚                                             
                                 โ”‚    parent                                   
                                 โ”‚                                             
                                 โ”‚                                             
               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                           
               โ”‚      valueCtx{k: 1, v: 1234}      โ”‚                           
               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                           
                                 โ–ฒ                                             
                                 โ”‚                                             
                                 โ”‚                                             
                                 โ”‚    parent                                   
                                 โ”‚                                             
                                 โ”‚                                             
                                 โ”‚                                             
               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                           
               โ”‚      valueCtx{k: 2, v: 2345}      โ”‚                           
               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                           
                                 โ–ฒ                                             
                                 โ”‚                                             
                  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                  
                  โ”‚                                         โ”‚                  
                  โ”‚                                         โ”‚                  
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚      valueCtx{k: 3, v: 3456}      โ”‚     โ”‚      valueCtx{k: 3, v: 4567}      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”             
             โ”‚   x   โ”‚                                   โ”‚   y   โ”‚             
             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

valueCtx ๅˆ†ๆž

valueCtx ไธป่ฆๅฐฑๆ˜ฏ็”จๆฅๆบๅธฆ่ดฏ็ฉฟๆ•ดไธช้€ป่พ‘ๆต็จ‹็š„ๆ•ฐๆฎ็š„๏ผŒๅœจๅˆ†ๅธƒๅผ็ณป็ปŸไธญๆœ€ๅธธ่ง็š„ๅฐฑๆ˜ฏ trace_id๏ผŒๅœจไธ€ไบ›ไธšๅŠก็ณป็ปŸไธญ๏ผŒไธ€ไบ›ไธšๅŠกๆ•ฐๆฎ้กนไนŸ้œ€่ฆ่ดฏ็ฉฟๆ•ดไธช่ฏทๆฑ‚็š„็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผŒๅฆ‚ order_id๏ผŒpayment_id ็ญ‰ใ€‚

WithValue ๆ—ถๅณไผš็”Ÿๆˆ valueCtx๏ผš

func WithValue(parent Context, key, val interface{}) Context {
	if key == nil {
		panic("nil key")
	}
	if !reflectlite.TypeOf(key).Comparable() {
		panic("key is not comparable")
	}
	return &valueCtx{parent, key, val}
}

key ๅฟ…้กปไธบ้ž็ฉบ๏ผŒไธ”ๅฏๆฏ”่พƒใ€‚

ๅœจๆŸฅๆ‰พๅ€ผ๏ผŒๅณๆ‰ง่กŒ Value ๆ“ไฝœๆ—ถ๏ผŒไผšๅ…ˆๅˆคๆ–ญๅฝ“ๅ‰่Š‚็‚น็š„ k ๆ˜ฏไธๆ˜ฏ็ญ‰ไบŽ็”จๆˆท็š„่พ“ๅ…ฅ k๏ผŒๅฆ‚ๆžœ็›ธ็ญ‰๏ผŒ่ฟ”ๅ›ž็ป“ๆžœ๏ผŒๅฆ‚ๆžœไธ็ญ‰๏ผŒไผšไพๆฌกๅ‘ไธŠไปŽๅญ่Š‚็‚นๅ‘็ˆถ่Š‚็‚น๏ผŒไธ€็›ดๆŸฅๆ‰พๅˆฐๆ•ดไธช ctx ็š„ๆ นใ€‚ๆฒกๆœ‰ๆ‰พๅˆฐ่ฟ”ๅ›ž nilใ€‚ๆ˜ฏไธ€ไธช้€’ๅฝ’ๆต็จ‹๏ผš

func (c *valueCtx) Value(key interface{}) interface{} {
	if c.key == key {
		return c.val
	}
	return c.Context.Value(key) // ่ฟ™้‡Œๅ‘็”Ÿไบ†้€’ๅฝ’๏ผŒc.Context ๅฐฑๆ˜ฏ c.parent
}

้€š่ฟ‡ๅˆ†ๆž๏ผŒctx ่ฟ™ไนˆ่ฎพ่ฎกๆ˜ฏไธบไบ†่ƒฝ่ฎฉไปฃ็ ๆฏๆ‰ง่กŒๅˆฐไธ€ไธช็‚น้ƒฝๅฏไปฅๆ นๆฎๅฝ“ๅ‰ๆƒ…ๅ†ตๅตŒๅ…ฅๆ–ฐ็š„ไธŠไธ‹ๆ–‡ไฟกๆฏ๏ผŒไฝ†ๆˆ‘ไปฌไนŸๅฏไปฅ็œ‹ๅˆฐ๏ผŒๅฆ‚ๆžœๆˆ‘ไปฌๆฏๆฌกๅŠ ไธ€ไธชๆ–ฐๅ€ผ้ƒฝๆ‰ง่กŒ WithValue ไผšๅฏผ่‡ด ctx ็š„ๆ ‘็š„ๅฑ‚ๆ•ฐ่ฟ‡้ซ˜๏ผŒๆŸฅๆ‰พๆˆๆœฌๆฏ”่พƒ้ซ˜ O(H)ใ€‚

ๅพˆๅคšไธšๅŠกๅœบๆ™ฏไธญ๏ผŒๆˆ‘ไปฌๅธŒๆœ›ๅœจ่ฏทๆฑ‚ๅ…ฅๅฃๅญ˜ๅ…ฅๅ€ผ๏ผŒๅœจ่ฏทๆฑ‚่ฟ‡็จ‹ไธญ้šๆ—ถๅ–็”จใ€‚่ฟ™ๆ—ถๅ€™ๆˆ‘ไปฌๅฏไปฅๅฐ† value ไฝœไธบไธ€ไธช map ๆ•ดไฝ“ๅญ˜ๅ…ฅใ€‚

context.WithValue(context.Background(), info,
	 map[string]string{"order_id" : "111", "payment_id" : "222"}
)

ไฝฟ็”จ cancelCtx ๅ–ๆถˆๆต็จ‹

cancelCtx ไฝฟ็”จ

ๅœจๆฒกๆœ‰ ctx ็š„ๆ—ถไปฃ๏ผŒๆˆ‘ไปฌๆƒณ่ฆๅ–ๆถˆไธ€ไธช go ๅ‡บๅŽป็š„ๅ็จ‹ๆ˜ฏๅพˆ้šพ็š„๏ผŒๅ› ไธบ go func() ่ฟ™ไธชๆ“ไฝœๆฒกๆœ‰ไปปไฝ•่ฟ”ๅ›ž๏ผŒๆ‰€ไปฅๆˆ‘ไปฌไนŸๆฒกๆœ‰ๅŠžๆณ•ๅŽป่ทŸ่ธช่ฟ™ไนˆไธ€ไธชๆ–ฐๅˆ›ๅปบ็š„ goroutineใ€‚

ๆœ‰ไบ† cancelCtx ไน‹ๅŽ๏ผŒๆˆ‘ไปฌๆƒณ่ฆๅ–ๆถˆๅฐฑๆฏ”่พƒ็ฎ€ๅ•ไบ†๏ผš

package main

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

func main() {
	jobChan := make(chan struct{})
	ctx, cancelFn := context.WithCancel(context.TODO())
	worker := func() {
		jobLoop:
		for {
			select {
			case <-jobChan:
				fmt.Println("do my job")
			case <-ctx.Done():
				fmt.Println("parent call me to quit")
				break jobLoop
			}
		}
	}

	// start worker
	go worker()

	// stop all worker
	cancelFn()
	time.Sleep(time.Second)
}

ไธ่ฟ‡ๅ–ๆถˆๆ“ไฝœไธ€ๅฎšๆ˜ฏ้œ€่ฆ fork ๅ‡บ็š„ goroutine ๆœฌ่บซ่ฆๅšไธ€ไบ›้…ๅˆๅŠจไฝœ็š„๏ผš

select {
	case <-jobChan:
		// do my job
		fmt.Println("do my job")
	case <-ctx.Done():
		// parent want me to quit
		fmt.Println("parent call me to quit")
		break jobLoop
}

่ฟ™้‡Œๆˆ‘ไปฌไธ€่พนๆถˆ่ดน่‡ชๅทฑ็š„ job channel๏ผŒไธ€่พน่ฟ˜้œ€่ฆ็›‘ๅฌ ctx.Done()๏ผŒๅฆ‚ๆžœไธ็›‘ๅฌ ctx.Done()๏ผŒ้‚ฃๆ˜พ็„ถไนŸๅฐฑไธ็Ÿฅ้“ไป€ไนˆๆ—ถๅ€™้œ€่ฆ้€€ๅ‡บไบ†ใ€‚

cancelCtx ๅˆ†ๆž

// 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
}

ไฝฟ็”จ WithCancel ๅฏไปฅๅพ—ๅˆฐไธ€ไธช cancelCtx:

// WithCancel returns a copy of parent with a new Done channel. The returned
// context's Done channel is closed when the returned cancel function is called
// or when the parent context's Done channel is closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
	c := newCancelCtx(parent)
	propagateCancel(parent, &c)
	return &c, func() { c.cancel(true, Canceled) }
}
// propagateCancel arranges for child to be canceled when parent is.
func propagateCancel(parent Context, child canceler) {
	if parent.Done() == nil {
		return // ่ฏดๆ˜Ž็ˆถ่Š‚็‚นไธ€ๅฎšๆ˜ฏ emptyCtx๏ผŒๆˆ–่€…็”จๆˆท่‡ชๅทฑๅฎž็Žฐ็š„ context.Context
	}
	if p, ok := parentCancelCtx(parent); ok {
		p.mu.Lock()
		if p.err != nil {
			// cancel ๅ‘็”Ÿ็š„ๆ—ถๅ€™๏ผŒerr ๅญ—ๆฎตไธ€ๅฎšไผš่ขซ่ต‹ๅ€ผ๏ผŒ่ฟ™้‡Œ่ฏดๆ˜Ž็ˆถ่Š‚็‚นๅทฒ็ป่ขซ่ต‹ๅ€ผไบ†
			child.cancel(false, p.err)
		} else {
			if p.children == nil {
				p.children = make(map[canceler]struct{})
			}
			p.children[child] = struct{}{} // ๆŠŠๅฝ“ๅ‰ cancelCtx ่ฟฝๅŠ ๅˆฐ็ˆถ่Š‚็‚นๅŽป
		}
		p.mu.Unlock()
	} else { // ๅฆ‚ๆžœ็”จๆˆทๆŠŠ context ๅŒ…ๅœจไบ†่‡ชๅทฑ็š„ struct ๅ†…ๅฐฑไผšๅˆฐ่ฟ™ไธชๅˆ†ๆ”ฏใ€‚
		go func() {
			select {
			case <-parent.Done(): // ็ˆถ่Š‚็‚นๅ–ๆถˆ๏ผŒ้œ€่ฆๅฐ†่ฟ™ไธชๅ–ๆถˆๆŒ‡ไปคๅŒๆญฅ็ป™ๅญ่Š‚็‚น
				child.cancel(false, parent.Err())
			case <-child.Done(): // ๅญ่Š‚็‚นๅ–ๆถˆ็š„่ฏ๏ผŒๅฐฑไธ็”จ็ญ‰็ˆถ่Š‚็‚นไบ†
			}
		}()
	}
}

parentCancelCtx ๅช่ฏ†ๅˆซ context ๅŒ…ๅ†…็š„ไธ‰็ง็ฑปๅž‹๏ผŒๅฆ‚ๆžœ็”จๆˆท่‡ชๅทฑ็š„็ฑปๅฎž็Žฐไบ† context.Context ๆŽฅๅฃ๏ผŒๆˆ–่€…ๆŠŠ ctx ๅŒ…ๅœจไบ†่‡ชๅทฑ็š„็ฑปๅž‹ๅ†…๏ผŒๆˆ–่€…ๆ˜ฏ emptyCtx๏ผŒ้‚ฃ่ฟ™้‡Œๅง‹็ปˆ่ฟ”ๅ›ž็š„ๆ˜ฏ nil๏ผŒfalseใ€‚

func parentCancelCtx(parent Context) (*cancelCtx, bool) {
	for {
		switch c := parent.(type) {
		case *cancelCtx:
			return c, true
		case *timerCtx:
			return &c.cancelCtx, true
		case *valueCtx:
			parent = c.Context
		default:
			return nil, false
		}
	}
}

ไฝฟ็”จ timerCtx ่ถ…ๆ—ถๅ–ๆถˆ

timerCtx ไฝฟ็”จ

็”จ WithDeadline ๅ’Œ WithTimeout ้ƒฝๅฏไปฅ็”Ÿๆˆไธ€ไธช timerCtx:

package main

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

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(), 50*time.Millisecond)
	defer cancel()

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

}

่ฟ™ๆ˜ฏไปŽๅฎ˜ๆ–น็š„ example ้‡Œๆ‘˜ๅ‡บๆฅ็š„ไพ‹ๅญ๏ผŒWithTimeout ๅ…ถๅฎžๅบ•ๅฑ‚ๆ˜ฏ็”จ WithDeadline ๅฎž็Žฐ็š„ใ€‚

timerCtx ๅˆ†ๆž

// 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
}

็”จ WithTimeout ๅ’Œ WithDeadline ้ƒฝไผš็”Ÿๆˆไธ€ไธช timerCtxใ€‚

func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {
	if cur, ok := parent.Deadline(); ok && cur.Before(d) {
		// ๅฆ‚ๆžœ็ˆถ่Š‚็‚น็š„ dealine ๆ›ด้ ๅ‰๏ผŒ้‚ฃๅฝ“็„ถไปฅ็ˆถ่Š‚็‚น็š„ไธบๅ‡†๏ผŒๅฝ“ๅ‰่Š‚็‚น็š„ deadline ๅฏไปฅๆŠ›ๅผƒ
		return WithCancel(parent)
	}
	c := &timerCtx{
		cancelCtx: newCancelCtx(parent),
		deadline:  d,
	}

  // ๅ‘ไธŠๅ†’ๆณก๏ผŒๆŠŠๅฝ“ๅ‰่Š‚็‚น็š„ cancel ๅ‡ฝๆ•ฐๅ…ณ่”ๅˆฐ็ˆถ cancelCtx ่Š‚็‚นไธŠ
	propagateCancel(parent, c)
	dur := time.Until(d)
	if dur <= 0 {
		c.cancel(true, DeadlineExceeded) // ๅทฒ็ป่ถ…ๆ—ถไบ†๏ผŒ้€€ๅ‡บๅง
		return c, func() { c.cancel(false, Canceled) }
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err == nil { // ่ฏดๆ˜Ž็ˆถ่Š‚็‚นๅˆฐ็Žฐๅœจ่ฟ˜ๆฒกๆœ‰ๅ–ๆถˆๅ‘ข
		c.timer = time.AfterFunc(dur, func() {
			c.cancel(true, DeadlineExceeded) // ่ฟ™ไธชๆ–นๆณ•ๅˆฐๆ—ถ้—ดไบ†ไน‹ๅŽไผš่‡ชๅŠจๆ‰ง่กŒ๏ผŒๅฝ“ๅ‰็š„ goroutine ไธไผš่ขซ้˜ปๅกž
		})
	}
	return c, func() { c.cancel(true, Canceled) }
}
  • ๆฏๆฌกๆ‰ง่กŒ้ƒฝไผšๅˆ›ๅปบๆ–ฐ็š„ timer
  • ๅญ่Š‚็‚น็š„ deadline ไธ€ๅฎšไธไผš่ถ…่ฟ‡็ˆถ่Š‚็‚น
  • ๅˆ›ๅปบ่ฟ‡็จ‹ไธญๅ‘็Žฐๅทฒ็ป่ฟ‡ๆœŸไบ†๏ผŒ็ซ‹ๅˆป่ฟ”ๅ›ž

ๆ ‘ๅฝข็ป“ๆž„

ไธบไป€ไนˆ่ฎพ่ฎกๆˆๆ ‘ๅฝข็ป“ๆž„ๅ‘ขใ€‚ๅ› ไธบๅฏนไบŽ fork-join ็š„ๆจกๅž‹(Go ็š„ๅŽŸๅœฐ go func ๅฐฑๆ˜ฏ่ฟ™็งๆจกๅž‹)ๆฅ่ฏด๏ผŒ็จ‹ๅบไปฃ็ ็š„ๆ‰ง่กŒๆœฌๆฅๅฐฑๆ˜ฏๆ ‘ๅฝข็š„ใ€‚ๅœจ่ฟ›ๅ…ฅใ€้€€ๅ‡บๆŸไธชๅญ่Š‚็‚น็š„ๆ—ถๅ€™๏ผŒๆ—ข่ฆๅŠ ๆ–ฐ็š„ๆ•ฐๆฎ๏ผŒๅˆไธ่ƒฝๅฝฑๅ“็ˆถ่Š‚็‚น็š„ๆ•ฐๆฎ๏ผŒๆ‰€ไปฅ่ฟ™็ง้“พๅผๆ ‘ๅฝข็ป“ๆž„ๅฏไปฅๅฎŒ็พŽๅœฐๅŒน้…ใ€‚

                             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                             โ”‚                    โ”Œโ”€โ”        โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ–ถโ””โ”€โ”˜        โ”‚
โ”‚                        โ”‚   โ”‚ โ•‘                   โ–ฒ         โ”‚
โ”‚                        โ”‚   โ”‚ โ•‘                   โ”ƒ         โ”‚
โ”‚                        โ”‚   โ”‚ โ•‘     โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ซ         โ”‚
โ”‚                        โ”‚   โ”‚ โ•‘     โ”ƒ             โ”ƒ         โ”‚
โ”‚func() {    โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฌโ•โ•โ•โ•ฌโ•โ•     โ”ƒ             โ”—โ”โ”โ”โ”โ”โ”“   โ”‚
โ”‚                        โ”‚   โ”‚       โ”ƒ                   โ”ƒ   โ”‚
โ”‚                        โ”‚   โ”‚      โ”Œโ”€โ”                  โ”ƒ   โ”‚
โ”‚    go func1(){}() โ•โ•โ•โ•โ•โ•ฌโ•โ•โ•โ•ฌโ•โ•โ•โ•โ•โ–ถโ””โ”€โ”˜                  โ”ƒ   โ”‚
โ”‚                        โ”‚   โ”‚                           โ”ƒ   โ”‚
โ”‚                        โ”‚   โ”‚                           โ”ƒ   โ”‚
โ”‚                        โ”‚   โ”‚                          โ”Œโ”€โ”  โ”‚
โ”‚    go func2(){โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฌโ•โ•โ•โ•ฌโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ–ถโ””โ”€โ”˜  โ”‚
โ”‚                        โ”‚   โ”‚                           โ–ฒ   โ”‚
โ”‚                        โ”‚   โ”‚                           โ”ƒ   โ”‚
โ”‚                        โ”‚   โ”‚                           โ”ƒ   โ”‚
โ”‚        go func3(){}()โ•โ•โ•ฌโ•โ•โ•โ•ฌโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—                 โ”ƒ   โ”‚
โ”‚                        โ”‚   โ”‚         โ•‘                 โ”ƒ   โ”‚
โ”‚                        โ”‚   โ”‚         โ•‘                 โ”ƒ   โ”‚
โ”‚                        โ”‚   โ”‚         โ•‘                โ”Œโ”€โ”  โ”‚
โ”‚    }()                 โ”‚   โ”‚         โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ–ถโ””โ”€โ”˜  โ”‚
โ”‚}                       โ”‚   โ”‚                               โ”‚
โ”‚                        โ”‚   โ”‚                               โ”‚
โ”‚                        โ”‚   โ”‚                               โ”‚
โ”‚                        โ”‚   โ”‚                               โ”‚
โ”‚                        โ”‚   โ”‚                               โ”‚
โ”‚                        โ”‚   โ”‚                               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

ๅ–ๆถˆๆŸไธช็ˆถ่Š‚็‚น๏ผŒๅˆ่ƒฝๅคŸ็”จๆ ‘็š„้ๅŽ†็ฎ—ๆณ•ๅฐ†่ฏฅๅ–ๆถˆๆŒ‡ไปคไผ ๅฏผๅˆฐๆ•ดๆฃตๆ ‘ๅŽปใ€‚

             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                         
             โ”‚ emptyCtx โ”‚                                         
             โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค                                         
             โ”‚cancelCtx โ”‚                                         
             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                         
                   โ–ฒ                                              
                   โ”‚                                              
                   โ”‚                                              
                   โ”‚                                              
                   โ”‚                                              
                   โ”‚                                              
             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                         
             โ”‚cancelCtx โ”‚                           cancel here   
             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                         
                   โ–ฒ                                      โ”ƒ       
                   โ”‚                                      โ”ƒ       
                   โ”‚                                      โ”ƒ       
      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                        โ”ƒ       
      โ”‚                          โ”‚                        โ”ƒ       
      โ”‚                         โ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ข             โ”ƒ       
      โ”‚                    โ–ขโ–ขโ–ขโ–ขโ–ข โ”‚           โ–ขโ–ขโ–ขโ–ขโ–ข        โ”ƒ       
      โ”‚                โ–ขโ–ขโ–ขโ–ข      โ”‚               โ–ขโ–ขโ–ขโ–ข     โ”ƒ       
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ–ขโ–ขโ–ขโ–ข   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”             โ–ขโ–ขโ–ข   โ”ƒ       
โ”‚cancelCtx โ”‚       โ–ขโ–ข      โ”‚cancelCtx โ”‚โ—€โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”›       
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ–ขโ–ข       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                 โ–ขโ–ข        
                 โ–ขโ–ข              โ–ฒ                       โ–ขโ–ข       
                 โ–ข      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ–ขโ–ข      
                โ–ข       โ”‚             โ”‚            โ”‚       โ–ข      
               โ–ขโ–ข โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ–ข      
               โ–ข  โ”‚cancelCtx โ”‚  โ”‚cancelCtx โ”‚ โ”‚cancelCtx โ”‚ โ–ข       
              โ–ข   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ขโ–ขโ–ข        
              โ–ข                                     โ–ขโ–ขโ–ขโ–ข          
              โ–ขโ–ข                                โ–ขโ–ขโ–ขโ–ขโ–ข             
               โ–ข                            โ–ขโ–ขโ–ขโ–ขโ–ข                 
               โ–ขโ–ขโ–ข                      โ–ขโ–ขโ–ขโ–ข                      
                 โ–ขโ–ขโ–ขโ–ขโ–ขโ–ข           โ–ขโ–ขโ–ขโ–ขโ–ขโ–ข                          
                      โ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ขโ–ข

ๅฆ‚ๅ›พ๏ผŒๆ ‘ไธŠๆŸไธช่Š‚็‚น cancel ไน‹ๅŽ๏ผŒไผš้กบไพฟ่ฐƒ็”จๅ…ถ children ๆ•ฐ็ป„ไธญๆ‰€ๆœ‰ๅญ่Š‚็‚น็š„ๅ–ๆถˆๅ‡ฝๆ•ฐ๏ผŒ่ฏฅๅ–ๆถˆๆ“ไฝœไธ€็›ดไผ ๅฏผๅˆฐๅถๅญ่Š‚็‚นใ€‚

traps

cancelCtx ็š„ๆ€ง่ƒฝ้—ฎ้ข˜

ๅฆ‚ๆžœไธ้€š่ฟ‡ WithCancel ๆฅๅคๅˆถ้€š็Ÿฅ channel๏ผŒๅคงๅฎถ้ƒฝไฝฟ็”จๅŒไธ€ไธช ctx.Done๏ผŒ้‚ฃไนˆๅฎž้™…ไธŠๆ˜ฏๅœจไบ‰ไธ€ๆŠŠๅคง้”ใ€‚

package main

import "context"
import "time"

func main() {
	ctx, _ := context.WithCancel(context.TODO())
	for i := 0; i < 100; i++ {
		go func() {
			select {
			case <-ctx.Done():
			}
		}()
	}
	time.Sleep(time.Hour)
}

ๅœจไธ€ไบ›ๅœบๆ™ฏๅฏ่ƒฝไผšๆœ‰ๆ€ง่ƒฝ้—ฎ้ข˜ใ€‚

ctx ็š„ๆ‰“ๅฐ panic

http ไธญ็š„ ctx ่ฟ˜ๅกžไบ† map๏ผŒๆ‰“ๅฐไผš้€ ๆˆ fatalใ€‚

package main

import (
    "fmt"
    "net/http"
    "reflect"
)

func panic(w http.ResponseWriter, r *http.Request) {
    server := r.Context().Value(http.ServerContextKey).(*http.Server)
    v := reflect.ValueOf(*server)

    for i := 0; i < v.NumField(); i++ {
        if name := v.Type().Field(i).Name; name != "activeConn" {
            continue
        }
        fmt.Println(v.Field(i))
    }
}

func main() {
    http.HandleFunc("/", panic)
    err := http.ListenAndServe(":9090", nil)
    if err != nil {
        fmt.Println(err)
    }
}

ๆ€ป็ป“

ctx ็š„็ป“ๆž„ๆ˜พ็„ถๆ˜ฏๆ นๆฎไปฃ็ ็š„ๆ‰ง่กŒๆจกๅž‹ๆฅ่ฎพ่ฎก็š„๏ผŒ่™ฝ็„ถ่ฎพ่ฎกๅพ—ๆฏ”่พƒๅทงๅฆ™๏ผŒไฝ†ๅ› ไธบๅฐ†ๅ–ๆถˆๅ’ŒไธŠไธ‹ๆ–‡ๆบๅธฆๅŠŸ่ƒฝๆททๅˆๅœจไธ€่ตท๏ผŒๅœจไธ€ไบ›ๆƒ…ๅ†ตไธ‹่ฟ˜ๆ˜ฏไผš็ป™ๆˆ‘ไปฌๅŸ‹ไบ›ๆฏ”่พƒ้š่”ฝ็š„ๅ‘ใ€‚ไฝฟ็”จๆ—ถ้œ€่ฆๅคšๅคšๆณจๆ„ใ€‚