Безопасно ли пропускать ctx.Done () при использовании пакета Go Context? - PullRequest
0 голосов
/ 03 апреля 2020

Я ищу способ "отменить" метод, основанный на том, сколько времени прошло с момента его выполнения. Пакет контекста, кажется, является хорошим способом достижения этой цели, вместо того, чтобы выписывать все логи "wait for x time of pass" logi c.

Код, который я использую для Параметры теста и узнать, как работает контекст в Go, выглядит следующим образом.

func runit() {
    var i uint8
    for i < 5 {
        fmt.Println(i)
        i++
        time.Sleep(1 * time.Second)
    }
}

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()

    go runit()

    select {
    case <-time.After(3 * time.Second):
        fmt.Println(ctx.Err())
        return
    }
}

Go Playground Link

Примеры и учебники, которые я вижу, содержат case <-ctx.Done(): но в моей ситуации ctx.Done() будет выполнено до истечения трех секунд.

Безопасно ли его отключать, поскольку в этом случае основная функция завершит работу sh и, в свою очередь, отменит Goroutine

Ответы [ 2 ]

0 голосов
/ 03 апреля 2020

Чтобы ответить на вопрос в заголовке: можно безопасно оставить ctx.Done(). Канал, возвращаемый Done(), не всегда необходим, просто во многих случаях использования контекста подпрограмма go ожидает один или несколько каналов и должна также ожидать контекст, чтобы он мог прервать свою работу. Другими словами, он ожидает канала, возвращенного из ctx.Done() и других каналов, используя оператор select.

Но если вы просто запускаете некоторые вызовы в потенциально долгосрочном l oop тогда вам не нужно использовать Done(), но вы можете просто проверить, возвращает ли Err() ненулевое значение.

Надеюсь, я прав, предполагая, что это то, что вам нужно:

func runit(ctx context.Context) {
    for i := 0;  i < 5; i++ {
        fmt.Println(i)
        time.Sleep(1 * time.Second)
        if ctx.Err() != nil {
            return // abort the calcs
        }
    }
}

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    runit(ctx)
    fmt.Println(ctx.Err())
}

Или, может быть, вы хотите попробовать контекст в выборе:

    select {
    case <-ctx.Done():
        fmt.Println("Context cancelled (after 1 second)")
    case <-time.After(3 * time.Second):
        fmt.Println("Not Done")
    }
0 голосов
/ 03 апреля 2020

Когда время ожидания истекает, он закрывает канал, возвращаемый ctx.Done(), поэтому вы можете проверить, истек ли срок действия контекста.

select {
    case <-time.After(3 * time.Second):
        fmt.Println(ctx.Err())
        return
    case <-ctx.Done():
        // Context timed out
        return
}

Ваш контекст истекает через секунду, но выбор будет подождите 3 секунды, чтобы получить тайм-аут контекста, вы должны использовать канал Done().

Без использования канала Done() бессмысленно использовать контекст с тайм-аутом. Это единственный способ получить событие тайм-аута.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...