context.Context
может только передать сообщение о том, что произошел тайм-аут или отмена. Он не может фактически остановить любые процедуры (подробности см. отмена операции блокировки в Go). Сама программа отвечает за проверку тайм-аута и отмены, и прерывает работу раньше.
У вас есть все oop, которое безоговорочно повторяется 10 раз и что-то печатает. И вы проверяете тайм-аут только после l oop.
. Вы должны переместить проверку контекста в l oop:
func F(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
for i := 0; i < 10; i++ {
select {
case <-ctx.Done():
fmt.Println("TIME OUT")
cancel()
return ctx.Err()
default:
time.Sleep(1 * time.Second)
fmt.Println("No: ", i)
}
}
fmt.Println("ALL DONE")
return nil
}
С этим изменением результат будет ( попробуйте это на игровой площадке Go ):
No: 0
No: 1
No: 2
No: 3
TIME OUT
context deadline exceeded
Примечание: если вы видите напечатанное "No: 3"
, это может произойти или не произойти, поскольку любая итерация занимает 1 секунду, а время ожидания 3 секунды = 3 * задержка итерации, поэтому, будет ли таймаут первым или четвертая итерация начнется первой, будет "racy". Если вы уменьшите время ожидания до 2900 мс, "No: 3"
не будет напечатано.