我创造了作品链。他们要在我的额外线程内工作。为此,我使用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();
}
}
}
答案 0 :(得分:2)
您必须使用NotOnFaulted任务继续选项。
由于TaskContinuationOptions使用Flags属性修饰,因此您可以将NotFaulted与其他选项结合使用。
var awaiter = task.ContinueWith(_ => act2(),
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnFaulted)
.ContinueWith(_ => act3(),
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnFaulted)
.GetAwaiter();
即使您使用 async / await 关键字,此方法仍然有效(但您可以摆脱 GetAwaiter 调用)
答案 1 :(得分:2)
代码试图以非常规方式使用任务,几乎就像它们是线程一样。它们不是 - 任务是一个将被安排在线程池线程上运行的作业,而不是线程本身。调用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;
您无需明确访问awaiter。对.Result
的最终调用将返回整数结果,如果之前的任务之一出现故障,则抛出AggregateException