Gram z tymi zadaniami Windows 8 WinRT i próbuję anulować zadanie przy użyciu poniższej metody i do pewnego momentu działa. Metoda CancelNotification DOES jest wywoływana, co powoduje, że myślisz, że zadanie zostało anulowane, ale w tle zadanie jest nadal uruchomione, a po jego zakończeniu stan zadania jest zawsze ukończony i nigdy nie jest anulowany. Czy istnieje sposób, aby całkowicie zatrzymać zadanie, gdy zostanie anulowane?
private async void TryTask()
{
CancellationTokenSource source = new CancellationTokenSource();
source.Token.Register(CancelNotification);
source.CancelAfter(TimeSpan.FromSeconds(1));
var task = Task<int>.Factory.StartNew(() => slowFunc(1, 2), source.Token);
await task;
if (task.IsCompleted)
{
MessageDialog md = new MessageDialog(task.Result.ToString());
await md.ShowAsync();
}
else
{
MessageDialog md = new MessageDialog("Uncompleted");
await md.ShowAsync();
}
}
private int slowFunc(int a, int b)
{
string someString = string.Empty;
for (int i = 0; i < 200000; i++)
{
someString += "a";
}
return a + b;
}
private void CancelNotification()
{
}
Odpowiedzi:
Przeczytaj informacje na temat anulowania (które zostało wprowadzone w .NET 4.0 i od tego czasu w dużej mierze nie uległo zmianie) oraz wzorca asynchronicznego opartego na zadaniach , który zawiera wytyczne dotyczące używania
CancellationToken
zasync
metodami.Podsumowując, należy przekazać
CancellationToken
do każdej metody, która obsługuje anulowanie, a ta metoda musi ją okresowo sprawdzać.źródło
CancellationToken
ma wszystkie zaczepy niezbędne do współdziałania z niestandardowymi systemami anulowania, ale nic nie może anulować metody, której nie można anulować.Wait
lubResult
wasync
metodach; powinieneś zawsze używaćawait
zamiast tego, co poprawnie rozpakuje wyjątek.CancellationToken.IsCancellationRequested
a zamiast tego sugeruje rzucanie wyjątków?Lub, aby uniknąć modyfikacji
slowFunc
(powiedzmy, że nie masz dostępu do kodu źródłowego na przykład):Możesz także użyć ładnych metod rozszerzeń z https://github.com/StephenCleary/AsyncEx i wygląda to tak prosto, jak:
źródło
ConfigureAwait
przeciwnym razie możesz zranić się w aplikacjach UI.using
.Jedynym przypadkiem, który nie został omówiony, jest sposób obsługi anulowania w ramach metody asynchronicznej. Weźmy na przykład prosty przypadek, w którym musisz przesłać jakieś dane do usługi, aby coś obliczył, a następnie zwróci niektóre wyniki.
Jeśli chcesz obsługiwać anulowanie, najłatwiejszym sposobem byłoby przekazanie tokenu i sprawdzenie, czy został on anulowany między każdym wywołaniem metody asynchronicznej (lub przy użyciu ContinueWith). Jeśli są to bardzo długo trwające połączenia, możesz chwilę poczekać, aby je anulować. Stworzyłem małą metodę pomocniczą, która zamiast tego kończyła się niepowodzeniem po anulowaniu.
Aby go użyć, po prostu dodaj
.WaitOrCancel(token)
do dowolnego wywołania asynchronicznego:Pamiętaj, że nie zatrzyma to zadania, na które czekałeś, i będzie kontynuowane. Będziesz musiał użyć innego mechanizmu, aby go zatrzymać, takiego jak
CancelAsync
wywołanie w przykładzie, lub jeszcze lepiej przekazać to samoCancellationToken
do,Task
aby ostatecznie obsłużyć anulowanie. Próba przerwania wątku nie jest zalecana .źródło
UploadDataAsync
Może kontynuować w tle, ale po zakończeniu nie wykona połączenia,CalculateAsync
ponieważ ta część już przestała czekać). Może to być problematyczne, ale nie musi, zwłaszcza jeśli chcesz ponowić operację. JeśliCancellationToken
jest to możliwe, preferowaną opcją jest przejście przez całą drogę w dół.Chcę tylko dodać do już zaakceptowanej odpowiedzi. Utknąłem w tym, ale szedłem inną drogą, jeśli chodzi o obsługę całego zdarzenia. Zamiast uruchamiać czekaj, dodaję ukończoną procedurę obsługi do zadania.
Gdzie program obsługi zdarzeń wygląda tak
Dzięki tej trasie cała obsługa jest już wykonana za Ciebie, gdy zadanie jest anulowane, po prostu wyzwala procedurę obsługi zdarzenia i możesz zobaczyć, czy zostało anulowane.
źródło