Pisząc aplikację wielowątkowe często istnieje potrzeba raportowania aktualnego postępu lub przerwania obliczeń „z zewnątrz”.
Klasa BackgroundWorker dostarcza do tego gotowe metody. Jednak jak to zrobić gdy pracujemy z klasą Task?
1) Raportowanie:
Jednym z możliwych sposobów, rozwiązania tego problemu, jest użycie obiektów implementujących interface IProgress<T>.
Metoda, która ma wykonywać się asynchronicznie, jako parametr powinna przyjmować obiekty typu IProgress<T>:
Task DoSomeWorkAsync(IProgress<int> progress)
Obiekt ten zawiera metodę Report(T), która jako parametr przyjmuje typ generyczny w tym przypadku będzie to int.
Wywołanie tych obliczeń wygląda w następujący sposób:
var progressIndicator = new Progress<int>(ReportProgress); await DoSomeWorkAsync(progressIndicator, token); . . . private Task DoSomeWorkAsync(IProgress<int> progress) { return Task.Run(() => { for (int i = 0; i < int.MaxValue; i++) { progress.Report(i); } }); }
do tego metoda raportująca:
private void ReportProgress(int value) { Console.WriteLine("Current progress: {0}", value); }
2) Przerwanie obliczeń:
Do metody asynchronicznej przekazujemy dodatkowy parametr: CancellationToken.
Dzięki temu możemy, wewnątrz metody, sprawdzać czy nie przyszło żądanie o przerwanie obliczeń.
Wystarczy sprawdzić stan flagi IsCancellationRequested.
private Task DoSomeWorkAsync(CancellationToken cancellationToken) { return Task.Run(() => { for (int i = 0; i < int.MaxValue; i++) { if (cancellationToken.IsCancellationRequested) { break; } } }); }
wywołanie metody w tym przypadku wygląda tak:
var cts = new CancellationTokenSource(); var token = cts.Token; await DoSomeWorkAsync(token);
oraz żądanie przerwania:
cts.Cancel();
Cały działający kod z przykładem (pomimo tego, że ma on tylko 55 linii) jak zawsze dostępny na GitHub 😉
Be First to Comment