Правильно ли я реализую этот буфер с помощью таймера C #? - PullRequest
0 голосов
/ 06 февраля 2019

У меня есть служба, которая подписывается на обновления в хранилище.При получении сообщения об обновлении службе необходимо перезагрузить некоторые данные из хранилища.

Однако многие сообщения об обновлениях могут быть получены за короткий период времени.Поэтому я хочу создать буферное / временное окно, это будет означать, что только одна перезагрузка произойдет за тот период, когда поступило много сообщений об обновлении.

Я создал очень грубый контур:

class TestService
{
    private Timer scheduledReloadTimer;

    public void AttemptReload()
    {
        if (scheduledReloadTimer == null)
        {
            Console.WriteLine("Scheduling reload...");

            scheduledReloadTimer = new Timer(Reload, null, 10000, Timeout.Infinite);
        }
        else
        {
            Console.WriteLine("Reload already scheduled for this period...");
        }
    }

    private void Reload(object stateInfo)
    {
        scheduledReloadTimer.Dispose();
        scheduledReloadTimer = null;

        Console.WriteLine("Doing reload..");
    }
}

Достаточно ли хорошо используется проверка нуля на таймере, чтобы проверить, запланирована ли перезагрузка?

Правильно ли я утилизирую таймер?

Есть ли что-то еще, чего мне здесь не хватает,особенно в отношении безопасности потоков?

Я видел другой ответ на стекопоток, который предлагает использовать Reactive Extensions для достижения этой цели: https://stackoverflow.com/a/42887221/67357 но является ли это избыточным?

1 Ответ

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

У вас есть потенциальная проблема с безопасностью потоков.Быстрое решение состоит в том, чтобы создать область блокировки потока вокруг критических частей вашего кода, чтобы гарантировать, что, пока вы проверяете / создаете и устанавливаете переменную таймера, никакой другой поток не может войти туда и запустить тот же процесс параллельно:

class TestService
{
    private Timer scheduledReloadTimer;
    private object timerLock = new object();

    public void AttemptReload()
    {
        lock (timerLock)
        {
            if (scheduledReloadTimer == null)
            {
                Console.WriteLine("Scheduling reload...");

                scheduledReloadTimer = new Timer(Reload, null, 10000, Timeout.Infinite);
            }
            else
            {
                Console.WriteLine("Reload already scheduled for this period...");
            } 
        }
    }

    private void Reload(object stateInfo)
    {
        lock (timerLock)
        {
            scheduledReloadTimer.Dispose();
            scheduledReloadTimer = null; 
        }

        Console.WriteLine("Doing reload..");
    }
}

Реактивные расширения являются хорошим способом решения этой проблемы регулирования - поскольку код уже написан для вас.

Другим подходом может быть изменениеВызов AttemptReload просто сбрасывает интервал на таймере (если reloadTimer! = Null), по сути, отодвигая вызов события таймера при каждом последующем вызове AttemptReload.

Таким образом, таймер определенно не сработаетдо последнего вызова AttemptReload + 10000 миллисекунд.

...