我正在尝试使用 this FAQ 中所述的取消 token 。这是我最初的想法:
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()
返回bool
。 - 如何正确创建和销毁 token 以允许多次启动和取消操作?
- 如何处理任务中的任务?控制台中显示“done”,但任务 (AsyncLoginTask) 尚未完成。
最佳答案
I'm trying to make use of cancellation tokens as described in this FAQ.
该博客文章使用动态任务并行性(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()
}
关于c# - 使用异步任务取消任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44260010/