发生异常时如何打断Task链?
How to break the chain of Task when an exception occurs?
我创建作品链。他们将在我的附加线程中工作。为此,我使用 Task
。另外,如果发生任何异常,我想中断链的工作并将其抛出到调用线程中。但是我看到我的链条没有断, act2
和 act3
也完成了。
我该如何解决?
using System;
using System.Threading.Tasks;
namespace Bushman.Sandbox.Threads {
class Program {
static void Main(string[] args) {
Console.Title = "Custom thread";
try {
// First work
Action act1 = () => {
for (int i = 0; i < 5; i++) {
// I throw the exeption here
if (i == 3) throw new Exception("Oops!!!");
Console.WriteLine("Do first work");
}
};
// Second work
Action act2 = () => {
for (int i = 0; i < 5; i++)
Console.WriteLine(" Do second work");
};
// Third work
Func<int> act3 = () => {
for (int i = 0; i < 5; i++)
Console.WriteLine(" Do third work");
return 12345;
};
Task task = new Task(act1);
// Build the chain of the works
var awaiter = task.ContinueWith(_ => act2(),
TaskContinuationOptions.ExecuteSynchronously)
.ContinueWith(_ => act3(),
TaskContinuationOptions.ExecuteSynchronously)
.GetAwaiter();
Console.WriteLine("Work started...");
// launch the chain
task.Start();
// Here I get some result
int result = awaiter.GetResult(); // 12345
if (task.IsCanceled || task.IsFaulted) {
throw task.Exception.InnerException;
}
Console.WriteLine("The result: {0}",
result.ToString());
}
catch (Exception ex) {
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
Console.ResetColor();
}
Console.WriteLine("Press any key for exit...");
Console.ReadKey();
}
}
}
您必须使用 NotOnFaulted 任务继续选项。
由于 TaskContinuationOptions 用 Flags 属性修饰,您可以将 NotFaulted 与其他选项结合使用。
var awaiter = task.ContinueWith(_ => act2(),
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnFaulted)
.ContinueWith(_ => act3(),
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnFaulted)
.GetAwaiter();
即使你使用了async/await关键字,这个方法仍然有效(但是你去掉了GetAwaiter调用)
代码试图以一种非常规的方式使用任务,就好像它们是线程一样。它们不是 - 任务是一项将被安排到 运行 线程池线程上的作业,而不是线程本身。调用 Task.Start
不会执行任何操作,它将 安排 其委托给线程上的 运行。这就是为什么永远不会使用构造函数创建任务的原因。
开始和协调任务的最简单方法是使用Task.Run和async/await
,例如:
public static async Task<int> MyMethodAsync()
{
try
{
await Task.Run(()=>act1());
await Task.Run(()=>act2());
var result=await Task.Run(()=>act3());
return result;
}
catch (Exception exc)
{
//Do something
}
}
您不能在控制台应用程序的 Main 函数上使用 async/await
,因此您必须按以下方式调用该方法:
var result=MyMethodAsync().Result;
对任务调用 .Wait()
或 .Result
会重新抛出其中引发的任何异常。
没有 async/await
,你需要使用ContinueWith
并实际检查上一个任务的结果。如果你只是想停止处理,你可以通过 TaskContinuationOptions.NotOnFaulted :
var result = Task.Run(()=>act1())
.ContinueWith( t1=>act2(),TaskContinuationOptions.NotOnFaulted)
.ContinueWith( t2=>act3(),TaskContinuationOptions.NotOnFaulted)
.Result;
您不需要获得对等待者的显式访问权限。对 .Result
的最终调用将 return 整数结果或抛出 AggregateException
如果之前的任务之一出错
我创建作品链。他们将在我的附加线程中工作。为此,我使用 Task
。另外,如果发生任何异常,我想中断链的工作并将其抛出到调用线程中。但是我看到我的链条没有断, act2
和 act3
也完成了。
我该如何解决?
using System;
using System.Threading.Tasks;
namespace Bushman.Sandbox.Threads {
class Program {
static void Main(string[] args) {
Console.Title = "Custom thread";
try {
// First work
Action act1 = () => {
for (int i = 0; i < 5; i++) {
// I throw the exeption here
if (i == 3) throw new Exception("Oops!!!");
Console.WriteLine("Do first work");
}
};
// Second work
Action act2 = () => {
for (int i = 0; i < 5; i++)
Console.WriteLine(" Do second work");
};
// Third work
Func<int> act3 = () => {
for (int i = 0; i < 5; i++)
Console.WriteLine(" Do third work");
return 12345;
};
Task task = new Task(act1);
// Build the chain of the works
var awaiter = task.ContinueWith(_ => act2(),
TaskContinuationOptions.ExecuteSynchronously)
.ContinueWith(_ => act3(),
TaskContinuationOptions.ExecuteSynchronously)
.GetAwaiter();
Console.WriteLine("Work started...");
// launch the chain
task.Start();
// Here I get some result
int result = awaiter.GetResult(); // 12345
if (task.IsCanceled || task.IsFaulted) {
throw task.Exception.InnerException;
}
Console.WriteLine("The result: {0}",
result.ToString());
}
catch (Exception ex) {
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
Console.ResetColor();
}
Console.WriteLine("Press any key for exit...");
Console.ReadKey();
}
}
}
您必须使用 NotOnFaulted 任务继续选项。
由于 TaskContinuationOptions 用 Flags 属性修饰,您可以将 NotFaulted 与其他选项结合使用。
var awaiter = task.ContinueWith(_ => act2(),
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnFaulted)
.ContinueWith(_ => act3(),
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnFaulted)
.GetAwaiter();
即使你使用了async/await关键字,这个方法仍然有效(但是你去掉了GetAwaiter调用)
代码试图以一种非常规的方式使用任务,就好像它们是线程一样。它们不是 - 任务是一项将被安排到 运行 线程池线程上的作业,而不是线程本身。调用 Task.Start
不会执行任何操作,它将 安排 其委托给线程上的 运行。这就是为什么永远不会使用构造函数创建任务的原因。
开始和协调任务的最简单方法是使用Task.Run和async/await
,例如:
public static async Task<int> MyMethodAsync()
{
try
{
await Task.Run(()=>act1());
await Task.Run(()=>act2());
var result=await Task.Run(()=>act3());
return result;
}
catch (Exception exc)
{
//Do something
}
}
您不能在控制台应用程序的 Main 函数上使用 async/await
,因此您必须按以下方式调用该方法:
var result=MyMethodAsync().Result;
对任务调用 .Wait()
或 .Result
会重新抛出其中引发的任何异常。
没有 async/await
,你需要使用ContinueWith
并实际检查上一个任务的结果。如果你只是想停止处理,你可以通过 TaskContinuationOptions.NotOnFaulted :
var result = Task.Run(()=>act1())
.ContinueWith( t1=>act2(),TaskContinuationOptions.NotOnFaulted)
.ContinueWith( t2=>act3(),TaskContinuationOptions.NotOnFaulted)
.Result;
您不需要获得对等待者的显式访问权限。对 .Result
的最终调用将 return 整数结果或抛出 AggregateException
如果之前的任务之一出错