Срок контекста в Go
Кроме ручной отмены контекст можно
связать со сроком. Когда время вышло,
канал Done закрывается так же,
как при вызове функции отмены, и
ожидающие ветки должны выйти.
Команда со сроком тоже возвращает функцию отмены. Ее нужно вызвать, когда контекст больше не нужен, даже если срок уже сработал: так освобождаются внутренние таймеры.
Зададим короткий срок и дождемся отмены в воркере:
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context) {
<-ctx.Done()
fmt.Println("timeout")
}
func main() {
ctx, cancel := context.WithTimeout(
context.Background(),
50*time.Millisecond,
)
defer cancel()
go worker(ctx)
<-ctx.Done()
}
Программа печатает "timeout" и
заканчивается без ручного вызова отмены
в середине main: срок истек сам.
Срок можно комбинировать с ручной отменой:
кто первый закроет Done, тот и
остановит ветки. Ниже срок длиннее паузы,
но отмену вызывают раньше:
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(
context.Background(),
time.Second,
)
defer cancel()
go func() {
<-ctx.Done()
fmt.Println("end")
}()
time.Sleep(10 * time.Millisecond)
cancel()
<-ctx.Done()
}
Дан следующий код:
parent := context.Background()
go func(ctx context.Context) {
<-ctx.Done()
fmt.Println("late")
}(parent)
От parent получите контекст
со сроком тридцать миллисекунд,
передайте его в ветку, повесьте
функцию отмены на defer и
дождитесь Done в main.
Дан следующий код:
ctx, stop := context.WithTimeout(
context.Background(),
time.Millisecond,
)
_ = ctx
Допишите отложенный вызов stop
и скажите, зачем он нужен, если срок
уже истек.
Скажите, чем отмена по сроку отличается
от канала done без таймера,
который закрывают вручную в конце ветки.