c#中任务:Task、TaskFactory简单使用方法
作者:admin 日期:2012-02-25
上下文可以很好的在线程之间传递值
CallContext.LogicalSetData("Name", "Jackey");
string s = (string)CallContext.LogicalGetData("Name");
也可以用 ExecutionContext.SuppressFlow(); 来阻止上下文的流动
Task在并行计算中的作用很凸显,首次构造一个Task对象时,他的状态是Created。以后,当任务启动时,他的状态变成WaitingToRun。Task在一个线程上运行时,他的状态变成Running。任务停止运行,并等待他的任何子任务时,状态变成WaitingForChildrenToComplete。任务完全结束时,它进入以下三个状态之一:RanToCompletion,Canceled或者Faulted。一个Task<TResult>运行完成时,可通过Task<TResult>的Result属性来查询任务的结果,一个Task或者Task<TResult>出错时,可以查询Task的Exception属性来获得任务抛出的未处理的异常,该属性总是返回一个AggregateException对象,他包含所有未处理的异常。
为简化代码,Task提供了几个只读的Boolean属性,IsCanceled,IsFaulted,IsCompleted。注意,当Task处于RanToCompleted,Canceled或者Faulted状态时,IsCompleted返回True。为了判断一个Task是否成功完成,最简单的方法是
if(task.Status == TaskStatus.RanToCompletion)。
普通的Task调用 ,如果你想要有返回的结果,要使用Task<>
static void Main(string[] args)
{
Task<double> task = new Task<double>( o => Sum((double)o),5000.0);
task.Start();
task.Wait();
Console.WriteLine(task.Result);
Console.Read();
}
public static double Sum(double CountdownEvent)
{
double sum = 0;
for (double i = 0; i < CountdownEvent; i++)
{
sum += i;
}
return sum;
}
}
一个任务结束后启动另一个
static void Main(string[] args)
{
Task<double> one = new Task<double>(o => Sum((double)o), 5000.0);
one.Start();
Task two = one.ContinueWith(task => Console.WriteLine("The result is: {0}", one.Result));
Console.Read();
}
有父任务来来带动所有子任务
static void Main(string[] args)
{
Task<double[]> parent = new Task<double[]>(
() =>
{
var result = new double[3]; //create a array to save result
// parallel 3 child tasks
new Task(() => result[0] = Sum(10000.0), TaskCreationOptions.AttachedToParent).Start();
new Task(() => result[1] = Sum(20000.0), TaskCreationOptions.AttachedToParent).Start();
new Task(() => result[2] = Sum(30000.0), TaskCreationOptions.AttachedToParent).Start();
// return result
return result;
});
var cwt = parent.ContinueWith(parentTask => Array.ForEach(parentTask.Result, Console.WriteLine));
parent.Start();
Console.Read();
}
TaskFactory也是很有用的类,但是稍微复杂了一点,当一组Task对象来共享相同的状态时,可以使用这个类型
static void Main(string[] args)
{
// create task factory
Task parent = new Task(
() =>
{
var cts = new CancellationTokenSource();
var tf = new TaskFactory<double>(cts.Token,
TaskCreationOptions.AttachedToParent,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
// create paraller 3 tasks
var childTasks = new[] {
tf.StartNew( ()=> Sum(cts.Token,10000.0)),
tf.StartNew( ()=> Sum(cts.Token,20000.0)),
tf.StartNew(()=> Sum(cts.Token, Int32.MaxValue))};
// any child task throw exception, cancel all the child task
for (int i = 0; i < childTasks.Length; i++)
childTasks[i].ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted);
// after all tasks finish, get max from where were successfully, return the max
tf.ContinueWhenAll(
childTasks,
completeTask => completeTask.Where(
t => !t.IsFaulted && !t.IsCanceled).Max(t => t.Result),
CancellationToken.None)
.ContinueWith(t => Console.WriteLine("The Maximun is: {0}", t.Result),
TaskContinuationOptions.ExecuteSynchronously);
});
// show all the exceptions
parent.ContinueWith( p=>{
StringBuilder sb = new StringBuilder(
"The following exception(s) occurred: "+ Environment.NewLine);
foreach(var e in p.Exception.Flatten().InnerExceptions)
sb.AppendLine(" "+ e.GetType().ToString());
Console.WriteLine(sb.ToString());
}, TaskContinuationOptions.OnlyOnFaulted);
parent.Start();
parent.Wait();
Console.WriteLine("OK");
Console.Read();
}
public static double Sum(CancellationToken token, double CountdownEvent)
{
double sum = 0;
for (double i = 0; i < CountdownEvent; i++)
{
token.ThrowIfCancellationRequested(); //if source.cancel, this will throw OperationCanceledException
sum += i;
}
return sum;
}
这里我发现一个问题,我想测试 TaskContinuationOpstions枚举功能的时候总是有问题
task.ContinueWith(o =>
{ Console.WriteLine("Get Cancel..."); }, TaskContinuationOptions.OnlyOnCanceled);
怎么都不起作用,但是其他的选项倒是可以,索性
task.ContinueWith(o =>
{ if (cts.IsCancellationRequested) Console.WriteLine("Get Cancel..."); });
自己去判断一下是否是终止来实现。Method prototypes is below:
public static double Sum(CancellationToken token, double CountdownEvent)
{
while (true)
{
if (token.IsCancellationRequested)
return default(double);
Console.WriteLine(DateTime.Now.ToLongTimeString());
Thread.Sleep(1000);
}
return (double)DateTime.Now.Millisecond;
}
task.ContinueWith(o =>
{ if (cts.IsCancellationRequested) Console.WriteLine("Get Cancel..."); });





