select{ case<-time.After(time.Second*15):// This task takes 15 seconds fmt.Println("Finished the task") case<-ctxWithTimeout.Done(): fmt.Println("We've waited too long, let's move on!")// We only wait for 10 seconds }
funcgetUser(ctx context.Context, id int)(*User,error){ // Create a new context that will be cancelled if it takes more than 3 seconds ctx, cancel := context.WithTimeout(ctx,3*time.Second) defer cancel()
// Assume db.QueryRowContext is a function that executes a SQL query and returns a row row := db.QueryRowContext(ctx,"SELECT name FROM users WHERE id = ?", id)
var name string if err := row.Scan(&name); err !=nil{ returnnil, err }
funcscrapeWebsite(ctx context.Context, url string)(*html.Node,error){ // Create a new context that will be cancelled if it takes more than 5 seconds ctx, cancel := context.WithTimeout(ctx,5*time.Second) defer cancel()
// Create a request with the context req, err := http.NewRequestWithContext(ctx, http.MethodGet, url,nil) if err !=nil{ returnnil, err }
// Execute the request resp, err := http.DefaultClient.Do(req) if err !=nil{ returnnil, err } defer resp.Body.Close()
// Parse the response body as HTML return html.Parse(resp.Body), nill }
假設(shè)你有一個(gè)執(zhí)行長時(shí)間運(yùn)行任務(wù)的程序,但你希望能夠在程序接收到關(guān)閉信號(hào)時(shí)停止任務(wù)。這在一個(gè) Web 服務(wù)器中可能會(huì)很有用,當(dāng)關(guān)閉時(shí)必須停止提供請求并進(jìn)行清理。
funcdoTask(ctx context.Context){ for{ select{ case<-time.After(1* time.Second): // The task is done, we're ready to exit fmt.Println("Task is done") return case<-ctx.Done(): // The context was cancelled from the outside, clean up and exit fmt.Println("Got cancel signal, cleaning up") return } } }
funcmain(){ // Create a new context ctx, cancel := context.WithCancel(context.Background())
// Start the task in a goroutine go doTask(ctx)
// Wait for a shutdown signal <-getShutdownSignal()
// Cancel the context, which will stop the task cancel()
// Wait for a bit to allow the task to clean up time.Sleep(1* time.Second) }
funcexpensiveCalculation(ctx context.Context, resultChan chan<-int){ // Simulate a long-running calculation rand.Seed(time.Now().UnixNano()) sleepTime := time.Duration(rand.Intn(20)+1)* time.Second fmt.Printf("Calculation will take %s to complete\n", sleepTime)
time.Sleep(sleepTime)
select{ case<-ctx.Done(): // Context was cancelled, don't write to the channel return default: // Write the result to the channel resultChan <-42// replace with your actual calculation result } }
funcmain(){ // Create a context that will be cancelled after 10 seconds ctx, cancel := context.WithTimeout(context.Background(),10*time.Second) defer cancel()// The cancel should be deferred so resources are cleaned up
resultChan :=make(chanint)
// Start the expensive calculation in a separate goroutine go expensiveCalculation(ctx, resultChan)
// Wait for either the result or the context to be done select{ case res :=<-resultChan: // Got the result fmt.Printf("Calculation completed with result: %d\n", res) case<-ctx.Done(): // Context was cancelled fmt.Println("Calculation cancelled") } }
如果需要昂貴的計(jì)算(在本例中由 time.Sleep 模擬)在取消時(shí)立即停止,您必須設(shè)計(jì)計(jì)算以周期性地檢查上下文是否已取消。這通常在需要將計(jì)算分解為較小部分的情況下使用循環(huán)。如果計(jì)算不能分解,并需要一次運(yùn)行完畢,那么很遺憾,在 Go 中無法提前停止它。