Отмена контекста в Go
От родительского контекста можно получить
дочерний и функцию отмены. Пока отмену
не вызвали, дочерний ведет себя как
родитель; после вызова закрывается канал
Done, и все, кто ждал этот сигнал,
могут завершить работу.
Функцию отмены обычно вызывают через отложенный вызов, чтобы сигнал ушел и при обычном выходе, и при раннем возврате из функции.
Воркер ждет отмену и печатает знак
остановки; в main отмену вызывают
сразу после запуска ветки:
package main
import (
"context"
"fmt"
)
func worker(ctx context.Context) {
<-ctx.Done()
fmt.Println("stopped")
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go worker(ctx)
cancel()
}
На экране "stopped". Закрытие
канала Done разблокировало
ожидание в worker.
Тот же прием в цикле: на каждой итерации проверяют, не отменили ли контекст:
package main
import (
"context"
"fmt"
)
func tick(ctx context.Context) {
for i := 0; i < 5; i++ {
select {
case <-ctx.Done():
fmt.Println("break at", i)
return
default:
fmt.Println("step", i)
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go tick(ctx)
cancel()
}
Дан следующий код:
parent := context.Background()
go func(ctx context.Context) {
<-ctx.Done()
fmt.Println("halt")
}(parent)
От parent получите контекст
с ручной отменой, передайте его в
ветку, объявите функцию отмены с
отложенным вызовом и вызовите ее
из main.
Дан следующий код:
ctx, stop := context.WithCancel(context.Background())
_ = ctx
Скажите, что произойдет с каналом
Done у ctx, если
stop ни разу не вызвать до
конца программы.
Скажите, зачем функцию отмены часто
вешают на defer сразу после
получения пары контекст и отмена.