github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/context/example_test.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package context_test 6 7 import ( 8 "context" 9 "errors" 10 "fmt" 11 "net" 12 "sync" 13 "time" 14 ) 15 16 var neverReady = make(chan struct{}) // never closed 17 18 // This example demonstrates the use of a cancelable context to prevent a 19 // goroutine leak. By the end of the example function, the goroutine started 20 // by gen will return without leaking. 21 func ExampleWithCancel() { 22 // gen generates integers in a separate goroutine and 23 // sends them to the returned channel. 24 // The callers of gen need to cancel the context once 25 // they are done consuming generated integers not to leak 26 // the internal goroutine started by gen. 27 gen := func(ctx context.Context) <-chan int { 28 dst := make(chan int) 29 n := 1 30 go func() { 31 for { 32 select { 33 case <-ctx.Done(): 34 return // returning not to leak the goroutine 35 case dst <- n: 36 n++ 37 } 38 } 39 }() 40 return dst 41 } 42 43 ctx, cancel := context.WithCancel(context.Background()) 44 defer cancel() // cancel when we are finished consuming integers 45 46 for n := range gen(ctx) { 47 fmt.Println(n) 48 if n == 5 { 49 break 50 } 51 } 52 // Output: 53 // 1 54 // 2 55 // 3 56 // 4 57 // 5 58 } 59 60 // This example passes a context with an arbitrary deadline to tell a blocking 61 // function that it should abandon its work as soon as it gets to it. 62 func ExampleWithDeadline() { 63 d := time.Now().Add(shortDuration) 64 ctx, cancel := context.WithDeadline(context.Background(), d) 65 66 // Even though ctx will be expired, it is good practice to call its 67 // cancellation function in any case. Failure to do so may keep the 68 // context and its parent alive longer than necessary. 69 defer cancel() 70 71 select { 72 case <-neverReady: 73 fmt.Println("ready") 74 case <-ctx.Done(): 75 fmt.Println(ctx.Err()) 76 } 77 78 // Output: 79 // context deadline exceeded 80 } 81 82 // This example passes a context with a timeout to tell a blocking function that 83 // it should abandon its work after the timeout elapses. 84 func ExampleWithTimeout() { 85 // Pass a context with a timeout to tell a blocking function that it 86 // should abandon its work after the timeout elapses. 87 ctx, cancel := context.WithTimeout(context.Background(), shortDuration) 88 defer cancel() 89 90 select { 91 case <-neverReady: 92 fmt.Println("ready") 93 case <-ctx.Done(): 94 fmt.Println(ctx.Err()) // prints "context deadline exceeded" 95 } 96 97 // Output: 98 // context deadline exceeded 99 } 100 101 // This example demonstrates how a value can be passed to the context 102 // and also how to retrieve it if it exists. 103 func ExampleWithValue() { 104 type favContextKey string 105 106 f := func(ctx context.Context, k favContextKey) { 107 if v := ctx.Value(k); v != nil { 108 fmt.Println("found value:", v) 109 return 110 } 111 fmt.Println("key not found:", k) 112 } 113 114 k := favContextKey("language") 115 ctx := context.WithValue(context.Background(), k, "Go") 116 117 f(ctx, k) 118 f(ctx, favContextKey("color")) 119 120 // Output: 121 // found value: Go 122 // key not found: color 123 } 124 125 // This example uses AfterFunc to define a function which waits on a sync.Cond, 126 // stopping the wait when a context is canceled. 127 func ExampleAfterFunc_cond() { 128 waitOnCond := func(ctx context.Context, cond *sync.Cond) error { 129 stopf := context.AfterFunc(ctx, cond.Broadcast) 130 defer stopf() 131 cond.Wait() 132 return ctx.Err() 133 } 134 135 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond) 136 defer cancel() 137 138 var mu sync.Mutex 139 cond := sync.NewCond(&mu) 140 141 mu.Lock() 142 err := waitOnCond(ctx, cond) 143 fmt.Println(err) 144 145 // Output: 146 // context deadline exceeded 147 } 148 149 // This example uses AfterFunc to define a function which reads from a net.Conn, 150 // stopping the read when a context is canceled. 151 func ExampleAfterFunc_connection() { 152 readFromConn := func(ctx context.Context, conn net.Conn, b []byte) (n int, err error) { 153 stopc := make(chan struct{}) 154 stop := context.AfterFunc(ctx, func() { 155 conn.SetReadDeadline(time.Now()) 156 close(stopc) 157 }) 158 n, err = conn.Read(b) 159 if !stop() { 160 // The AfterFunc was started. 161 // Wait for it to complete, and reset the Conn's deadline. 162 <-stopc 163 conn.SetReadDeadline(time.Time{}) 164 return n, ctx.Err() 165 } 166 return n, err 167 } 168 169 listener, err := net.Listen("tcp", ":0") 170 if err != nil { 171 fmt.Println(err) 172 return 173 } 174 defer listener.Close() 175 176 conn, err := net.Dial(listener.Addr().Network(), listener.Addr().String()) 177 if err != nil { 178 fmt.Println(err) 179 return 180 } 181 defer conn.Close() 182 183 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond) 184 defer cancel() 185 186 b := make([]byte, 1024) 187 _, err = readFromConn(ctx, conn, b) 188 fmt.Println(err) 189 190 // Output: 191 // context deadline exceeded 192 } 193 194 // This example uses AfterFunc to define a function which combines 195 // the cancellation signals of two Contexts. 196 func ExampleAfterFunc_merge() { 197 // mergeCancel returns a context that contains the values of ctx, 198 // and which is canceled when either ctx or cancelCtx is canceled. 199 mergeCancel := func(ctx, cancelCtx context.Context) (context.Context, context.CancelFunc) { 200 ctx, cancel := context.WithCancelCause(ctx) 201 stop := context.AfterFunc(cancelCtx, func() { 202 cancel(context.Cause(cancelCtx)) 203 }) 204 return ctx, func() { 205 stop() 206 cancel(context.Canceled) 207 } 208 } 209 210 ctx1, cancel1 := context.WithCancelCause(context.Background()) 211 defer cancel1(errors.New("ctx1 canceled")) 212 213 ctx2, cancel2 := context.WithCancelCause(context.Background()) 214 215 mergedCtx, mergedCancel := mergeCancel(ctx1, ctx2) 216 defer mergedCancel() 217 218 cancel2(errors.New("ctx2 canceled")) 219 <-mergedCtx.Done() 220 fmt.Println(context.Cause(mergedCtx)) 221 222 // Output: 223 // ctx2 canceled 224 }