0、interface

  1. type Context interface {
  2. Deadline() (deadline time.Time, ok bool)
  3. Done() <-chan struct{}
  4. Err() error
  5. Value(key interface{}) interface{}
  6. }
  7. // 传播context
  8. // 主要是挂载到最近的为cancel context的父节点
  9. func propagateCancel(parent Context, child canceler) {
  10. done := parent.Done()
  11. if done == nil {
  12. return // 一般为root context
  13. }
  14. // 父节点是否已经被取消
  15. select {
  16. case <-done:
  17. // parent已经被cancel
  18. child.cancel(false, parent.Err())
  19. return
  20. default:
  21. }
  22. // 若ok为true,则找到并且为cancel context的父节点
  23. if p, ok := parentCancelCtx(parent); ok {
  24. p.mu.Lock()
  25. if p.err != nil {
  26. // 已经取消
  27. child.cancel(false, p.err)
  28. } else {
  29. if p.children == nil {
  30. p.children = make(map[canceler]struct{})
  31. }
  32. p.children[child] = struct{}{}
  33. }
  34. p.mu.Unlock()
  35. } else {
  36. // 启动单独的g监听父节点的done信息
  37. atomic.AddInt32(&goroutines, +1)
  38. go func() {
  39. select {
  40. case <-parent.Done():
  41. child.cancel(false, parent.Err())
  42. case <-child.Done():
  43. }
  44. }()
  45. }
  46. }
  47. // 获取parent cancel context
  48. func parentCancelCtx(parent Context) (*cancelCtx, bool) {
  49. // 此处逻辑有点向单例模式
  50. // 此处的判断也是为了提高效率
  51. done := parent.Done()
  52. // 若parent已经cancel或者为root context
  53. // 直接返回
  54. if done == closedchan || done == nil {
  55. return nil, false
  56. }
  57. // 通过&cancelCtxKey判断是否为cancel context
  58. p, ok := parent.Value(&cancelCtxKey).(*cancelCtx)
  59. if !ok {
  60. return nil, false
  61. }
  62. // 上锁判断是否关闭
  63. p.mu.Lock()
  64. ok = p.done == done
  65. p.mu.Unlock()
  66. if !ok {
  67. return nil, false
  68. }
  69. return p, true
  70. }
  71. // 从parent child里面移除child
  72. func removeChild(parent Context, child canceler) {
  73. p, ok := parentCancelCtx(parent)
  74. if !ok {
  75. return
  76. }
  77. p.mu.Lock()
  78. if p.children != nil {
  79. delete(p.children, child)
  80. }
  81. p.mu.Unlock()
  82. }
  83. func contextName(c Context) string {
  84. if s, ok := c.(stringer); ok {
  85. return s.String()
  86. }
  87. return reflectlite.TypeOf(c).String()
  88. }

1、root context

其实就是一个空context

  1. type emptyCtx int
  2. func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
  3. return
  4. }
  5. func (*emptyCtx) Done() <-chan struct{} {
  6. return nil
  7. }
  8. func (*emptyCtx) Err() error {
  9. return nil
  10. }
  11. func (*emptyCtx) Value(key interface{}) interface{} {
  12. return nil
  13. }
  14. func (e *emptyCtx) String() string {
  15. switch e {
  16. case background:
  17. return "context.Background"
  18. case todo:
  19. return "context.TODO"
  20. }
  21. return "unknown empty Context"
  22. }
  23. var (
  24. background = new(emptyCtx)
  25. todo = new(emptyCtx)
  26. )
  27. func Background() Context {
  28. return background
  29. }
  30. func TODO() Context {
  31. return todo
  32. }

2、cancel context

  1. var Canceled = errors.New("context canceled")
  2. // 可重复利用
  3. var closedchan = make(chan struct{})
  4. // 为了return cancelCtx自己(用&cancelCtxKey)
  5. var cancelCtxKey int
  6. func init() {
  7. close(closedchan)
  8. }
  9. type canceler interface {
  10. cancel(removeFromParent bool, err error)
  11. Done() <-chan struct{}
  12. }
  13. // 丢弃goroutine安全的result
  14. // goroutine安全
  15. // 幂等
  16. type CancelFunc func()
  17. type stringer interface {
  18. String() string
  19. }
  20. type cancelCtx struct {
  21. // parent context
  22. Context
  23. // 锁,保护如下3个属性
  24. mu sync.Mutex
  25. done chan struct{} // 懒式创建
  26. children map[canceler]struct{} // 子context
  27. err error // cacel error
  28. }
  29. func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
  30. if parent == nil {
  31. panic("cannot create context from nil parent")
  32. }
  33. c := newCancelCtx(parent)
  34. propagateCancel(parent, &c)
  35. return &c, func() { c.cancel(true, Canceled) }
  36. }
  37. func newCancelCtx(parent Context) cancelCtx {
  38. return cancelCtx{Context: parent}
  39. }
  40. // 获取value,若key为&cancelCtxKey返回自己
  41. // 否则调用parent context获取
  42. func (c *cancelCtx) Value(key interface{}) interface{} {
  43. if key == &cancelCtxKey {
  44. return c
  45. }
  46. return c.Context.Value(key)
  47. }
  48. // context是否被取消的chan
  49. // 若调用cancel,则close chan
  50. func (c *cancelCtx) Done() <-chan struct{} {
  51. c.mu.Lock()
  52. if c.done == nil {
  53. c.done = make(chan struct{})
  54. }
  55. d := c.done
  56. c.mu.Unlock()
  57. return d
  58. }
  59. // 返回context的错误信息
  60. func (c *cancelCtx) Err() error {
  61. c.mu.Lock()
  62. err := c.err
  63. c.mu.Unlock()
  64. return err
  65. }
  66. // context名称
  67. func (c *cancelCtx) String() string {
  68. return contextName(c.Context) + ".WithCancel"
  69. }
  70. func (c *cancelCtx) cancel(removeFromParent bool, err error) {
  71. // err必须设置
  72. if err == nil {
  73. panic("context: internal error: missing cancel error")
  74. }
  75. c.mu.Lock()
  76. // err不为nil,则context已经取消
  77. if c.err != nil {
  78. c.mu.Unlock()
  79. return
  80. }
  81. c.err = err
  82. // 设置done chan为可复用的closedchan
  83. // 此处之所以为空是因为有可能用户没有调用Done就调用了cancel
  84. if c.done == nil {
  85. c.done = closedchan
  86. } else {
  87. close(c.done)
  88. }
  89. // 依次关闭子节点
  90. // 并置child为nil
  91. for child := range c.children {
  92. child.cancel(false, err)
  93. }
  94. c.children = nil
  95. c.mu.Unlock()
  96. // 若需要移除,则从父parent移除
  97. if removeFromParent {
  98. removeChild(c.Context, c)
  99. }
  100. }

3、timeout/deadline context

  1. var DeadlineExceeded error = deadlineExceededError{}
  2. type deadlineExceededError struct{}
  3. func (deadlineExceededError) Error() string { return "context deadline exceeded" }
  4. func (deadlineExceededError) Timeout() bool { return true }
  5. func (deadlineExceededError) Temporary() bool { return true }
  6. type timerCtx struct {
  7. cancelCtx
  8. timer *time.Timer // Under cancelCtx.mu.
  9. deadline time.Time
  10. }
  11. // 指定Deadline的context,到期之后timer会自动关闭context
  12. func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {
  13. // 父context不能为空
  14. if parent == nil {
  15. panic("cannot create context from nil parent")
  16. }
  17. // 如果父节点的 dealine 更靠前,那当然以父节点的为准,当前节点的 deadline 可以抛弃
  18. if cur, ok := parent.Deadline(); ok && cur.Before(d) {
  19. return WithCancel(parent)
  20. }
  21. c := &timerCtx{
  22. cancelCtx: newCancelCtx(parent),
  23. deadline: d,
  24. }
  25. // 传播context
  26. propagateCancel(parent, c)
  27. // deadline已经到期则直接cancel
  28. dur := time.Until(d)
  29. if dur <= 0 {
  30. c.cancel(true, DeadlineExceeded)
  31. return c, func() { c.cancel(false, Canceled) }
  32. }
  33. // 否则增加timer
  34. c.mu.Lock()
  35. defer c.mu.Unlock()
  36. if c.err == nil {
  37. c.timer = time.AfterFunc(dur, func() {
  38. c.cancel(true, DeadlineExceeded)
  39. })
  40. }
  41. return c, func() { c.cancel(true, Canceled) }
  42. }
  43. func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
  44. return WithDeadline(parent, time.Now().Add(timeout))
  45. }
  46. func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
  47. return c.deadline, true
  48. }
  49. func (c *timerCtx) String() string {
  50. return contextName(c.cancelCtx.Context) + ".WithDeadline(" +
  51. c.deadline.String() + " [" +
  52. time.Until(c.deadline).String() + "])"
  53. }
  54. func (c *timerCtx) cancel(removeFromParent bool, err error) {
  55. // 调用cancel方法
  56. c.cancelCtx.cancel(false, err)
  57. // 移除
  58. if removeFromParent {
  59. removeChild(c.cancelCtx.Context, c)
  60. }
  61. // 关闭timer
  62. c.mu.Lock()
  63. if c.timer != nil {
  64. c.timer.Stop()
  65. c.timer = nil
  66. }
  67. c.mu.Unlock()
  68. }

4、value context

  1. func WithValue(parent Context, key, val interface{}) Context {
  2. if parent == nil {
  3. panic("cannot create context from nil parent")
  4. }
  5. if key == nil {
  6. panic("nil key")
  7. }
  8. if !reflectlite.TypeOf(key).Comparable() {
  9. panic("key is not comparable")
  10. }
  11. return &valueCtx{parent, key, val}
  12. }
  13. // 保存key/value
  14. type valueCtx struct {
  15. Context
  16. key, val interface{}
  17. }
  18. func (c *valueCtx) String() string {
  19. return contextName(c.Context) + ".WithValue(type " +
  20. reflectlite.TypeOf(c.key).String() +
  21. ", val " + stringify(c.val) + ")"
  22. }
  23. func (c *valueCtx) Value(key interface{}) interface{} {
  24. if c.key == key {
  25. return c.val
  26. }
  27. return c.Context.Value(key)
  28. }
  29. func stringify(v interface{}) string {
  30. switch s := v.(type) {
  31. case stringer:
  32. return s.String()
  33. case string:
  34. return s
  35. }
  36. return "<not Stringer>"
  37. }