如何在Golang中用Context WithTimeout取消长期运行的goroutines

99 阅读1分钟

在这个例子中,我们将运行一个goroutine并等待它完成工作。然而,我们只允许它在最多3秒内完成工作。如果需要更长的时间,我们将强制它超时。为此,我们将使用context.WithTimeout功能。

例子

package main

import (
	"context"
	"fmt"
	"math/rand"
	"time"
)

func main() {
	fmt.Println(">>>>> BEGIN")

	ctx, cancel := context.WithTimeout(context.Background(), 3 * time.Second)
	// Cancel even if everything goes fine without an error to release resources.
	defer cancel()

	ch := make(chan int)

	go doSomething(ch)

	select {
	case <-ctx.Done():
		fmt.Println("TIMEOUT:", ctx.Err())
	case t := <-ch:
		fmt.Printf("JOB DONE in %d seconds\n", t)
	}

	fmt.Println(">>>>> END")
}

func doSomething(ch chan<- int) {
	// Prevent picking up the same random number all the time for sleeping.
	rand.Seed(time.Now().UnixNano())

	// Pick a random number to simulate time it takes to finish the job.
	delay := rand.Intn(5)
	fmt.Printf("RUN: %d seconds\n", delay)
	time.Sleep(time.Duration(delay) * time.Second)

	ch<- delay
}

测试

>>>>> BEGIN
RUN: 1 seconds
JOB DONE in 1 seconds
>>>>> END

>>>>> BEGIN
RUN: 4 seconds
TIMEOUT: context deadline exceeded
>>>>> END

>>>>> BEGIN
RUN: 5 seconds
TIMEOUT: context deadline exceeded
>>>>> END

>>>>> BEGIN
RUN: 3 seconds
JOB DONE in 3 seconds
>>>>> END