有时候需要创建一组共享相同配置的Task对象,为了避免重复的将相同的参数传给每个Task,创建一个任务工厂很有必要
static void Main(string[] args)
{
//父任务
Task parent = new Task(
() =>
{
var cts = new CancellationTokenSource(); //标志
//任务工厂
var tf = new TaskFactory<int>(
cts.Token, TaskCreationOptions.AttachedToParent,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default
);
//创建子任务
var charltaske = new[]
{
//工厂任务直接开始一个 方法,因为是子任务所以,必须要父任务启动
tf.StartNew(()=>Sum(cts.Token,1000)),
tf.StartNew(()=>Sum(cts.Token,2000)),
tf.StartNew(()=>Sum(cts.Token,Int32.MaxValue))
};
//只要子任务其中的一个抛出异常,就取消全部的任务
for (int i = 0; i < charltaske.Length; i++)
{
charltaske[i].ContinueWith(t => {
cts.Cancel(); //所有任务终止,终止和失败都属于完成,到这里整个任务已经完成
Console.WriteLine("异常");
}, TaskContinuationOptions.OnlyOnFaulted);
}
//所有子任务完成后,查询出其中没有出错和取消的任务,并且返回最大值
//把最大的值传给另外一个任务来打印
//工厂任务调用ContinueWhenAll时 TaskContinuationOptions没有用,不管前置任务怎样都会执行
//ContinueWhenAll任务不属于子任务所以会和parent.ContinueWith同步执行,顺序会乱掉
tf.ContinueWhenAll(charltaske, compl => compl.Where(t => !t.IsFaulted && !t.IsCanceled).Max(t => t.Result),
CancellationToken.None).ContinueWith(t => Console.WriteLine("max is:" + t.Result)
, TaskContinuationOptions.None
);
});
//打印异常 整个任务执行的过车中如果有异常则运行这个方法
parent.ContinueWith(
p =>
{
StringBuilder sb = new StringBuilder("occurrde:" + Environment.NewLine);
foreach (var item in p.Exception.Flatten().InnerExceptions)
sb.AppendLine("" + item.GetType().ToString());
Console.WriteLine(sb.ToString());
}, TaskContinuationOptions.OnlyOnFaulted
);
parent.Start(); //父任务启动,子任务才会运行,这里是真正的启动任务,当所有子任务完成时,该任务才算完成
Console.ReadLine();
}
private static int Sum(CancellationToken cancellationToken, int p)
{
int sum = 0;
try
{
for (int i = 0; i < p; i++)
{
checked
{
sum += p;
}
}
Console.WriteLine("p=" + sum);
}
catch (Exception)
{
throw;
}
return sum;
}
输出:
注意:如果调用多任务延续(即:调用TaskFactory或TaskFactory<TResult>的静态ContinueWhenAll和ContinueWhenAny方法)时,NotOn和On六个标识或标识的组合都是无效的。也就是说,无论先驱任务是如何完成的,ContinueWhenAll和ContinueWhenAny都会执行延续任务。