Am'm a juca cu aceste Windows 8 WinRT sarcini, și am'm încercarea de a anula o sarcina folosind metoda de mai jos, și funcționează la un moment dat. La CancelNotification metoda NU se numește, care te face să crezi că sarcina a fost anulat, dar în fundal sarcina continuă să funcționeze, apoi, după ce-l's-a finalizat, starea de Sarcina este finalizată și nu anulate. Există o modalitate de a opri complet sarcina, atunci când l's-a anulat?
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()
{
}
Citiți pe Anulare (care a fost introdus în .NET 4.0 și este în mare parte neschimbat de atunci) și Task-Based Model Asincron, care oferă orientări privind modul de utilizare `CancellationToken cu "asincron" metode.
Pentru a rezuma, voi trece la un `CancellationToken în fiecare metoda care acceptă anularea, și că metoda trebuie să verifice periodic.
private async Task TryTask()
{
CancellationTokenSource source = new CancellationTokenSource();
source.CancelAfter(TimeSpan.FromSeconds(1));
Task<int> task = Task.Run(() => slowFunc(1, 2, source.Token), source.Token);
// (A canceled task will raise an exception when awaited).
await task;
}
private int slowFunc(int a, int b, CancellationToken cancellationToken)
{
string someString = string.Empty;
for (int i = 0; i < 200000; i++)
{
someString += "a";
if (i % 1000 == 0)
cancellationToken.ThrowIfCancellationRequested();
}
return a + b;
}
Sau, pentru a evita modificarea slowFunc
(daca nu - 't au acces la codul sursă, de exemplu):
var source = new CancellationTokenSource(); //original code
source.Token.Register(CancelNotification); //original code
source.CancelAfter(TimeSpan.FromSeconds(1)); //original code
var completionSource = new TaskCompletionSource<object>(); //New code
source.Token.Register(() => completionSource.TrySetCanceled()); //New code
var task = Task<int>.Factory.StartNew(() => slowFunc(1, 2), source.Token); //original code
//original code: await task;
await Task.WhenAny(task, completionSource.Task); //New code
Puteți folosi, de asemenea, frumos extensia metode de https://github.com/StephenCleary/AsyncEx și se pare la fel de simplu ca:
await Task.WhenAny(task, source.Token.AsTask());
Un caz care a't a fost acoperit este cum să se ocupe de anulare în interiorul de o metoda asincron. Luați, de exemplu, un caz simplu în care aveți nevoie pentru a încărca unele date de la un serviciu pentru a calcula ceva și apoi să se întoarcă rezultatele.
public async Task<Results> ProcessDataAsync(MyData data)
{
var client = await GetClientAsync();
await client.UploadDataAsync(data);
await client.CalculateAsync();
return await client.GetResultsAsync();
}
Dacă doriți să sprijine anulare atunci cel mai simplu mod ar fi să treacă într-un token-ul și verificați dacă acesta a fost anulat între fiecare metoda asincron apel (sau folosind ContinueWith). Dacă acestea sunt foarte lungă de funcționare apeluri deși ai putea fi un timp de așteptare pentru a anula. Am creat un mic ajutor metodă de a eșua în loc cât mai curând anulat.
public static class TaskExtensions
{
public static async Task<T> WaitOrCancel<T>(this Task<T> task, CancellationToken token)
{
token.ThrowIfCancellationRequested();
await Task.WhenAny(task, token.WhenCanceled());
token.ThrowIfCancellationRequested();
return await task;
}
public static Task WhenCanceled(this CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).SetResult(true), tcs);
return tcs.Task;
}
}
Deci, să-l folosească atunci doar adauga `.WaitOrCancel(token) la orice apel asincron:
public async Task<Results> ProcessDataAsync(MyData data, CancellationToken token)
{
Client client;
try
{
client = await GetClientAsync().WaitOrCancel(token);
await client.UploadDataAsync(data).WaitOrCancel(token);
await client.CalculateAsync().WaitOrCancel(token);
return await client.GetResultsAsync().WaitOrCancel(token);
}
catch (OperationCanceledException)
{
if (client != null)
await client.CancelAsync();
throw;
}
}
Rețineți că acest lucru nu va opri Sarcina ai fost de așteptare pentru și va continua să ruleze. Te'll nevoie pentru a utiliza un alt mecanism pentru a opri, cum ar fi CancelAsync
apel în exemplu, sau mai bine încă trece în aceeași `CancellationToken la "Sarcină", astfel încât se poate ocupa anularea în cele din urmă. Încercarea de a abandona filet e't recomandat.
Vreau doar pentru a adăuga la deja răspunsul acceptat. Am fost blocat pe aceasta, dar am fost de gând pe un drum diferit la manipularea eveniment complet. Mai degrabă decât de funcționare așteaptă, am adăuga un finalizată handler pentru sarcina.
Comments.AsAsyncAction().Completed += new AsyncActionCompletedHandler(CommentLoadComplete);
În cazul în care de tratare a evenimentelor arată astfel
private void CommentLoadComplete(IAsyncAction sender, AsyncStatus status )
{
if (status == AsyncStatus.Canceled)
{
return;
}
CommentsItemsControl.ItemsSource = Comments.Result;
CommentScrollViewer.ScrollToVerticalOffset(0);
CommentScrollViewer.Visibility = Visibility.Visible;
CommentProgressRing.Visibility = Visibility.Collapsed;
}
Cu acest traseu, tot manipulare este deja făcut pentru tine, atunci când sarcina este anulat doar declanșează event handler și puteți vedea dacă acesta a fost anulat acolo.