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);
}
}
}