대기중인 작업을 취소하는 방법?
이 Windows 8 WinRT 작업을하고 있는데 아래 방법을 사용하여 작업을 취소하려고하는데 어느 정도 작동합니다. CancelNotification 메소드 DOES가 호출되어 태스크가 취소되었다고 생각하지만 백그라운드에서 태스크가 계속 실행되고 완료된 후에는 태스크 상태가 항상 완료되고 절대 취소되지 않습니다. 작업이 취소 될 때 작업을 완전히 중단 할 수있는 방법이 있습니까?
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()
{
}
읽기 최대 취소 (.NET 4.0에 도입 된 이후 큰 변화가되었습니다)와 작업 기반 비동기 패턴 사용하는 방법에 대한 지침을 제공하고, CancellationToken
함께 async
방법을.
요약하면, CancellationToken
취소를 지원하는 각 메소드에 a 를 전달하면 해당 메소드가 주기적으로 확인해야합니다.
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;
}
또는 수정을 피하려면 slowFunc
(예를 들어 소스 코드에 액세스 할 수 없음) :
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
https://github.com/StephenCleary/AsyncEx 에서 멋진 확장 방법을 사용 하여 다음과 같이 간단하게 만들 수 있습니다.
await Task.WhenAny(task, source.Token.AsTask());
다루지 않은 한 가지 경우는 비동기 메서드 내에서 취소를 처리하는 방법입니다. 예를 들어, 서비스에 일부 데이터를 업로드하여 무언가를 계산 한 다음 결과를 반환해야하는 간단한 경우를 생각해보십시오.
public async Task<Results> ProcessDataAsync(MyData data)
{
var client = await GetClientAsync();
await client.UploadDataAsync(data);
await client.CalculateAsync();
return await client.GetResultsAsync();
}
If you want to support cancellation then the easiest way would be to pass in a token and check if it has been cancelled between each async method call (or using ContinueWith). If they are very long running calls though you could be waiting a while to cancel. I created a little helper method to instead fail as soon as canceled.
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;
}
}
So to use it then just add .WaitOrCancel(token)
to any async call:
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;
}
}
Note that this will not stop the Task you were waiting for and it will continue running. You'll need to use a different mechanism to stop it, such as the CancelAsync
call in the example, or better yet pass in the same CancellationToken
to the Task
so that it can handle the cancellation eventually. Trying to abort the thread isn't recommended.
I just want to add to the already accepted answer. I was stuck on this, but I was going a different route on handling the complete event. Rather than running await, I add a completed handler to the task.
Comments.AsAsyncAction().Completed += new AsyncActionCompletedHandler(CommentLoadComplete);
Where the event handler looks like this
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;
}
With this route, all the handling is already done for you, when the task is cancelled it just triggers the event handler and you can see if it was cancelled there.
참고URL : https://stackoverflow.com/questions/10134310/how-to-cancel-a-task-in-await
'Programing' 카테고리의 다른 글
Visual Studio 디버거에서 동적으로 할당 된 배열을 표시하는 방법은 무엇입니까? (0) | 2020.06.16 |
---|---|
Java에서 int []를 Integer []로 변환하는 방법? (0) | 2020.06.16 |
Java에서 int가 null 일 수 있습니까? (0) | 2020.06.16 |
Request.CreateResponse를 사용한 ASP.NET WebApi 장치 테스트 (0) | 2020.06.16 |
Visual Studio 2010 SP1에서 CSS 파일이 열리지 않습니까? (0) | 2020.06.16 |