使用异步任务取消任务
Task cancellation with async task
我正在尝试使用 this FAQ 中所述的取消令牌。这是我最初的想法:
private async void OnLoginButtonClicked(object sender, EventArgs e)
{
if (this.cancelToken == null)
{
this.cancelToken = new CancellationTokenSource();
}
try
{
bool loginSuccess = await AsyncLoginTask(this.cancelToken.Token);
if (loginSuccess)
{
// Show main page
}
}
catch (OperationCanceledException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
this.cancelToken = null;
}
}
private async Task<bool> AsyncLoginTask(CancellationToken cancellationToken = default(CancellationToken))
{
// Pass the token to HttpClient()
}
现在我修改了它,结果是这样的:
private async void OnLoginButtonClicked(object sender, EventArgs e)
{
this.cancelToken?.Dispose();
this.cancelToken = new CancellationTokenSource();
try
{
var ui = TaskScheduler.FromCurrentSynchronizationContext();
var loginTask = Task.Factory.StartNew(async () =>
{
bool loginSuccess = await AsyncLoginTask(this.cancelToken.Token);
}, this.cancelToken.Token);
var displayResults = loginTask.ContinueWith(resultTask =>
{
// How do I know if the login was successful?
// Because AsyncLoginTask() returns bool.
System.Diagnostics.Debug.WriteLine("done");
},
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
ui);
var displayCancelledTasks = loginTask.ContinueWith(resultTask =>
{
System.Diagnostics.Debug.WriteLine("canceled");
},
CancellationToken.None,
TaskContinuationOptions.OnlyOnCanceled, ui);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
问题:
- 如何知道登录是否成功?因为
AsyncLoginTask()
returnsbool
.
- 如何正确创建和销毁令牌以允许多次启动和取消操作?
- 任务中的任务怎么处理? "done" 显示在控制台中,而任务 (AsyncLoginTask) 尚未完成。
I'm trying to make use of cancellation tokens as described in this FAQ.
该博客 post 使用动态任务并行(StartNew
和 ContinueWith
)。动态任务并行是指当您有很多 CPU 绑定操作要做,并且在您已经处理它们之前不知道您有多少(即,您处理的每个操作都可以添加零个或多个额外的任务到同一进程)。
在您的例子中,您只有一个异步操作。因此,该文章中的方法对于您的用例来说是完全错误的。你原来的想法更正确。
你更想这样做:
private async void OnLoginButtonClicked(object sender, EventArgs e)
{
// Cancel the previous attempt (if any) and start a new one.
this.cts?.Cancel();
this.cts = new CancellationTokenSource();
try
{
bool loginSuccess = await AsyncLoginTask(this.cts.Token);
// Resolve race condition where user cancels just as it completed.
this.cts.Token.ThrowIfCancellationRequested();
if (loginSuccess)
{
// Show main page
}
}
catch (OperationCanceledException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
private async Task<bool> AsyncLoginTask(CancellationToken cancellationToken = default(CancellationToken))
{
// Pass the token to HttpClient()
}
我正在尝试使用 this FAQ 中所述的取消令牌。这是我最初的想法:
private async void OnLoginButtonClicked(object sender, EventArgs e)
{
if (this.cancelToken == null)
{
this.cancelToken = new CancellationTokenSource();
}
try
{
bool loginSuccess = await AsyncLoginTask(this.cancelToken.Token);
if (loginSuccess)
{
// Show main page
}
}
catch (OperationCanceledException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
this.cancelToken = null;
}
}
private async Task<bool> AsyncLoginTask(CancellationToken cancellationToken = default(CancellationToken))
{
// Pass the token to HttpClient()
}
现在我修改了它,结果是这样的:
private async void OnLoginButtonClicked(object sender, EventArgs e)
{
this.cancelToken?.Dispose();
this.cancelToken = new CancellationTokenSource();
try
{
var ui = TaskScheduler.FromCurrentSynchronizationContext();
var loginTask = Task.Factory.StartNew(async () =>
{
bool loginSuccess = await AsyncLoginTask(this.cancelToken.Token);
}, this.cancelToken.Token);
var displayResults = loginTask.ContinueWith(resultTask =>
{
// How do I know if the login was successful?
// Because AsyncLoginTask() returns bool.
System.Diagnostics.Debug.WriteLine("done");
},
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
ui);
var displayCancelledTasks = loginTask.ContinueWith(resultTask =>
{
System.Diagnostics.Debug.WriteLine("canceled");
},
CancellationToken.None,
TaskContinuationOptions.OnlyOnCanceled, ui);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
问题:
- 如何知道登录是否成功?因为
AsyncLoginTask()
returnsbool
. - 如何正确创建和销毁令牌以允许多次启动和取消操作?
- 任务中的任务怎么处理? "done" 显示在控制台中,而任务 (AsyncLoginTask) 尚未完成。
I'm trying to make use of cancellation tokens as described in this FAQ.
该博客 post 使用动态任务并行(StartNew
和 ContinueWith
)。动态任务并行是指当您有很多 CPU 绑定操作要做,并且在您已经处理它们之前不知道您有多少(即,您处理的每个操作都可以添加零个或多个额外的任务到同一进程)。
在您的例子中,您只有一个异步操作。因此,该文章中的方法对于您的用例来说是完全错误的。你原来的想法更正确。
你更想这样做:
private async void OnLoginButtonClicked(object sender, EventArgs e)
{
// Cancel the previous attempt (if any) and start a new one.
this.cts?.Cancel();
this.cts = new CancellationTokenSource();
try
{
bool loginSuccess = await AsyncLoginTask(this.cts.Token);
// Resolve race condition where user cancels just as it completed.
this.cts.Token.ThrowIfCancellationRequested();
if (loginSuccess)
{
// Show main page
}
}
catch (OperationCanceledException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
private async Task<bool> AsyncLoginTask(CancellationToken cancellationToken = default(CancellationToken))
{
// Pass the token to HttpClient()
}