Лучший способ вызвать функцию с переменным временем выполнения с минимальными интервалами в Голанге? - PullRequest
0 голосов
/ 05 февраля 2019

Я хочу выполнить функцию на не менее чем заданного интервала в Go, измеренного от начала одного вызова до начала следующего вызова.Сама функция будет различаться по времени выполнения.

Если функция выполняется дольше этого интервала, я хочу немедленно запустить ее снова.Но если / когда он в конечном итоге возобновляет выполнение менее чем за полный интервал, я хочу, чтобы он немедленно возобновил ожидание до следующей границы интервала.

Для контекста это ограничитель скорости - вызываемая функция можетлегко вращать процессор, но это не будет приносить дополнительную ценность, поскольку он взаимодействует с людьми, которые не могут реагировать так быстро.

Пример для ясности (interval == 20ms в примере):

runtime:  15ms
wait:      5ms
runtime:  25ms
wait:      0ms
runtime:  25ms
wait:      0ms
runtime:  15ms
wait:      5ms <-- this is the important bit

Если я использую time.Ticker, я полагаю, что дополнительные «тики» либо будут помещены в очередь в канале Ticker.C (если он буферизован), что заставит его выполнять несколько вызовов без задержки при возобновлении, либо тикерWriter заблокирует запись в канал и в конечном итоге возобновит работу с чрезмерно большой задержкой для первого возобновления после вызова.

Сейчас я занимаюсь какой-то математикой, которая работает, но кажется, чтобыть не идиоматичным:

minDurationBetweenRuns := time.Millisecond * 100
for {
    lastRunTime := time.Now()

    DO_STUFF_HERE()

    durationSinceLastRun := time.Now().Sub(lastRunTime)
    if durationSinceLastRun < minDurationBetweenRuns {
        sleepTime := minDurationBetweenRuns - durationSinceLastRun
        if sleepTime > minDurationBetweenRuns {
            sleepTime = minDurationBetweenRuns
        }
        time.Sleep(sleepTime)
    }
}

1 Ответ

0 голосов
/ 05 февраля 2019

Во время написания вопроса я вспомнил, что источник «Голанг» очень легко читается ... и решил, что мне нужно просто взглянуть, прежде чем выглядеть глупо.Я доволен тем, что нашел:)

Комментарии в источник для time.Ticker говорит, что если тик-ридер отстает, он начнет сбрасывать тики, а не блокировать запись в канал(который имеет буфер только 1).Эффект этого состоит в том, чтобы вернуть вещи «на ходу» сразу после того, как мы пропустили один или несколько тиков.

Пример доказательства:

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.NewTicker(time.Millisecond * 50)
    for i := 0; i < 10; i++ {
        fmt.Printf("New invocation starting at %dms\n", time.Now().Round(time.Millisecond).Nanosecond()/int(time.Millisecond))
        if i%3 == 0 {
            fmt.Println("Executing for 25ms")
            time.Sleep(time.Millisecond * 25)
        } else {
            fmt.Println("Executing for 75ms")
            time.Sleep(time.Millisecond * 75)
        }
        fmt.Println("Waiting for ticker...")
        <-t.C
    }
    t.Stop()
}

Вывод:

New invocation starting at 0ms
Executing for 25ms
Waiting for ticker...
New invocation starting at 50ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 125ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 200ms
Executing for 25ms
Waiting for ticker...
New invocation starting at 250ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 325ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 400ms
Executing for 25ms
Waiting for ticker...
New invocation starting at 450ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 525ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 600ms
Executing for 25ms
Waiting for ticker...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...