我有以下代码,其中aTask
可以取消,但是我基本上需要等待它完成(以确保完整性),然后再将其抛出OperationCanceledException
给调用者。
public static void TaskCancellationTest() {
try {
Console.WriteLine("TaskCancellationTest started.");
var cts = new CancellationTokenSource();
var t = Task.Run(() => {
if (cts.Token.IsCancellationRequested) return;
Console.WriteLine("1");
Task.Delay(2000).Wait();
Console.WriteLine("2");
}).ContinueWith(task => {
if (cts.Token.IsCancellationRequested) return;
Console.WriteLine("3");
Task.Delay(2000).Wait();
Console.WriteLine("4");
});
Task.Run(() => {
Task.Delay(1000).Wait();
Console.WriteLine("Cancelling...");
cts.Cancel();
});
t.Wait();
try {
cts.Token.ThrowIfCancellationRequested();
}
catch (OperationCanceledException) {
Console.WriteLine("Gracefully canceled.");
}
Console.WriteLine("TaskCancellationTest completed.");
}
catch (Exception ex) {
Console.WriteLine("TaskCancellationTest... Failure: " + ex);
}
}
预期的结果是:
1
Cancelling...
2
Gracefully canceled.
它可以工作,但是我更愿意将传递CancellationToken
给方法,因为我知道这是一个更好的模式。我还希望能够观察方法体内的标记并调用ThrowIfCancellationRequested()
中止,而不必等待next ContinueWith(
)。
我正在使用下面的替代代码,该代码也有效,但是有什么办法可以OperationCanceledException
引发而不是AggregateException
?
如果我将CancellationToken传递给该WaitAll()
方法,则问题在于,它将OperationCanceledException
在取消令牌后立即抛出该异常,而不是等待任务t1
并t2
实际完成(它们将继续在后台运行),然后仅引发异常。
public static void TaskCancellationTest2() {
try {
Console.WriteLine("TaskCancellationTest2 started.");
var cts = new CancellationTokenSource();
var t1 = Task.Run(() => {
Console.WriteLine("1");
Task.Delay(2000).Wait();
Console.WriteLine("2");
}, cts.Token);
var t2 = t1.ContinueWith(task => {
Console.WriteLine("3");
Task.Delay(2000).Wait();
cts.Token.ThrowIfCancellationRequested();
Console.WriteLine("4");
}, cts.Token);
Task.Run(() => {
Task.Delay(1000).Wait();
Console.WriteLine("Cancelling...");
cts.Cancel();
});
try {
try {
Task.WaitAll(t1, t2);
}
catch (AggregateException ae) {
if (ae.InnerExceptions.Count == 1 && ae.InnerExceptions.Single() is OperationCanceledException) {
throw ae.InnerExceptions.Single();
}
throw;
}
}
catch (OperationCanceledException) {
Console.WriteLine("Gracefully canceled.");
}
Console.WriteLine("TaskCancellationTest2 completed.");
}
catch (Exception ex) {
Console.WriteLine("TaskCancellationTest2... Failure: " + ex);
}
}
我在这里准备了一个小提琴。
这个问题的标题与我的非常相似,但是很遗憾,所接受的答案与我的情况无关。
您是否知道有什么方法可以充分利用我想要的东西CancellationToken
?
我认为,如果CancellationToken
设置了TPL,则TPL旨在急于完成任务。您看到此行为的部分原因是因为您在打电话t.Wait(cts.Token)
。CancellationToken
即使设置了令牌,即使任务尚未完成,带a的重载也会停止等待。
这是用相同的ContinueWith
,如果你传递一个CancellationToken
任务能尽快为标记设置完成。
将您的代码更改为可以调用t.Wait()
且ContinueWith
没有令牌的代码,您将获得所需的行为。
public static void TaskCancellationTestNotWorking1()
{
try
{
Console.WriteLine("TaskCancellationTestNotWorking started.");
var cts = new CancellationTokenSource();
var t = Task.Run(() =>
{
Console.WriteLine("1");
Thread.Sleep(2000);
Console.WriteLine("2");
}, cts.Token).ContinueWith(task =>
{
Console.WriteLine("3");
Thread.Sleep(2000);
cts.Token.ThrowIfCancellationRequested();
Console.WriteLine("4");
});
Task.Run(() =>
{
Thread.Sleep(1000);
Console.WriteLine("Cancelling...");
cts.Cancel();
}, cts.Token);
try
{
t.Wait();
}
catch (OperationCanceledException)
{
Console.WriteLine("IsCanceled " + t.IsCanceled);
Console.WriteLine("IsCompleted " + t.IsCompleted);
Console.WriteLine("Gracefully canceled.");
}
catch (AggregateException)
{
Console.WriteLine("IsCanceled " + t.IsCanceled);
Console.WriteLine("IsCompleted " + t.IsCompleted);
Console.WriteLine("Gracefully canceled 1.");
}
Console.WriteLine("TaskCancellationTestNotWorking completed.");
}
catch (Exception ex)
{
Console.WriteLine("TaskCancellationTestNotWorking... Failure: " + ex);
}
}
您可能会觉得这篇文章很有用。如何取消不可取消的异步操作?
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句