IProgress <T>, как часто сообщать о прогрессе

При использовании IProgress<T> для отчета о прогрессе, должен ли он быть

  • ответственность за прогресс, связанный с предоставлением кода, ограничивает его отчеты о проделанной работе на "разумной" частоте, -или -
  • ответственность за конкретную реализацию IProgress<T> должна знать, что отчетность о прогрессе может быть на более высокой частоте, чем разумно для того, как она будет представлять этот прогресс.

Контекст вопроса: у меня есть код, который использует IProgress<T> для отчета о прогрессе, и он сообщает о прогрессе с очень высокой скоростью. Я хочу показать прогресс с индикатором выполнения пользовательского интерфейса. Если я использую предоставленную реализацию Progress<T> (которая публикует ход в UI SyncronizationContext), то это приводит к тому, что пользовательский интерфейс не реагирует (т.е. Столько сообщений отправлено в очередь сообщений, что пользователь не может даже щелкнуть по значку "Отмена" в диалоговом окне).

Итак,

  • Я мог бы исправить это, сообщив меньше, но что, если бы у меня была реализация IProgress<T>, которая только что написала прогресс в файле журнала (и могла обрабатывать высокую частоту отчетности). -или -
  • Я мог бы это исправить, создав собственную специфическую реализацию IProgress<T>, которая ограничивала, как часто я обрабатывал/сообщал о прогрессе. Предположительно, эта реализация запишет последний прогресс в потоке, отличном от UI, а затем (возможно) пользовательский интерфейс будет обновляться на основе таймера.

Ответы

Ответ 1

Напишите декоратор, который дросселирует вызовы. Таким образом, вы разделяете логику дросселирования и фактическую отчетность, и вы можете использовать ее для любой другой реализации IProgress<T>.

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

Я оставил логику дросселирования до вас. Вы можете сделать это на основе времени, количества вызовов или других критериев.

public class ProgressThrottler<in T>: IProgress<T> {
    public ProgressThrottler(IProgress<T> progress) {
        if (progress == null)
            throw new ArgumentNullException("progress");

        _progress = progress;
    }

    private readonly IProgress<T> _progress;

    public void Report(T value) {
        // Throttles the amount of calls
        bool reportProgressAfterThrottling = ...;

        if (reportProgressAfterThrottling) {
            _progress.Report(value);
        }
    }
}