.net 4包含新名称空间system.Threading.Tasks,它包含的类抽象出了线程功能。在后台使用ThreadPool.任务表示应完成的某个单元的工作。这个单元的工作可以在单独的线程中运行,也可以以同步方式启动一个任务,这需要等待主调线程。
使用任务不仅可以获得一个抽象层,还可以对底层线程进行很多控制。在安排需要完成的工作时,任务提供了非常大的灵活性。例如,可以定义连续的工作——在一个任务完成后该执行什么工作。这可以区分任务成功与否。
另外,还可以在层次结构中安排任务。例如,父任务可以创建新的子任务。这可以创建一种依赖关系,这样,取消父任务,也会取消其子任务。
1.启动任务
要启动任务,可以使用TaskFactory类或Task类的构造函数和startO方法。Task类的构造函数在创建任务上提供的灵活性较大。
在启动任务时,会创建Task类的一个实例,利用Action或Action
static void Main(string[] args)
{
//使用任务工厂
TaskFactory tf = new TaskFactory();
Task t1 =tf.StartNew(TaskMethod);
Task T2 = Task.Factory.StartNew(TaskMethod);
//使用Task构造函数
Task t3 = new Task(TaskMethod);
t3.Start();
Console.ReadKey();
}
static void TaskMethod()
{
Console.WriteLine("启动一个任务.。。");
Console.WriteLine("Task is:{0}",Task.CurrentId);
}
第一种方式使用实例化的TaskFactory类,在其中把TaskMedlodO方法传递给StartNew方法,就会立即启动任务。第二种方式使用Task类的构造函数。实例化Task对象时,任务不会立即运行,而是指定Created状态。接着调用Task类的Start方法,来启动任务。使用Task类时,除了调用Start方法,还可以调用RunSynchronously()方法。这样,任务也会启动,但在调用者的当前线程中它正在运行,调用者需要一直等待到该任务结束。
默认情况下,任务是异步运行的。
使用Task类的构造函数和TaskFactory类的StartNew方法时,都可以传递TaskCreationOptions枚举中的值。设置LongRunning选项,可以通知任务调度器,该任务需要较长时间执行,这样调度器更可能使用新线程。如果该任务应关联到父任务上,而父任务取消了,则该任务也应取消,此时应设置AuachToParent选项。PerferTairness的值表示,调度器应提取出已在等待的第一个任务。如果一个任务在另一个任务内部创建,这就不是默认情况。如果任务使用子任务创建了其他工作,子任务就优先于其他任务。它们不会排在线程池队列中的最后。如果这些任务应以公平的方式与所有其他任务一起处理,就设置该选项为PerferTairness。
Task t3 = new Task(TaskMethod,TaskCreationOptions.PreferFairness);
t3.Start();
2.连续任务
通过任务,可以指定在任务完成后,应开始运行另一个特定任务,例如,一个使用前一个任务的结果的新任务,如果前一个任务失败了,这个任务就应执行一些清理工作。
任务处理程序或者不带参数或者带一个对象参数,而连续处理程序有一个Task类型的参数,这里可以访问起始任务的相关信息:
static void Main(string[] args)
{
Task t1 = new Task(DoFirst);
Task t2 = t1.ContinueWith(DoSecond);
Task t3 = t1.ContinueWith(DoSecond);
Task t4 = t2.ContinueWith(DoSecond);
t1.Start();
Console.ReadKey();
}
static void DoFirst()
{
Console.WriteLine("启动一个任务.。。");
Console.WriteLine("Task is :{0}", Task.CurrentId);
Thread.Sleep(3000);
}
static void DoSecond(Task t )
{
Console.WriteLine("任务{0}完成",t.Id);
Console.WriteLine("this Task is :{0}", Task.CurrentId);
Thread.Sleep(3000);
}
无论前一个任务是如何结束的,前面的连续任务总是在前一个任务结束时启动。使用TaskCreationOptions枚举中的值,可以指定,连续任务只有在起始任务成功(或失败)结束时启动。一些可能的值是OnlyOnFaulted,NotOnFaulted,OnlyOnCanceled,NotOnCanceled和OnlyOnRanToCompletion.
Taskt2 = t1.ContinueWith(DoSecond, TaskCreationOptions.OnlyOnFaulted);
3.任务层次结构
利用任务连续性,可以在一个任务结束后启动另一个任务。任务也可以构成一个层次结构。一个任务启动一个新任务时,就启动了一个细子层次结构。
如果父任务在子任务之前结束,父任务的状态就显示为WaitingForChildrenToComplete。只要子任务也结束时,父任务的状态就变成RanToCompletion.当然,如果父任务用TaskCreationOptions枚举中的DetachedFormParent创建子任务时,这就无效。
取消父任务,也会取消子任务。取消架构后面提到。
4.任务的结果
任务结束时,它可以把一些有用的状态信息写到共享对象中。这个共享对象必须是线程安全的。
另一个选项是使用返回某个结果的任务。使用Task类的泛型版本,就可以定义返回某个结果的任务的返回类型。
为了返回某个结果任务调用的方法可以声明为带任意返回类型
static Tuple TaskWithResult(object division)
{
Tuple div = (Tuple)division;
int result = div.Item1 / div.Item2;
int reminder = div.Item1 % div.Item2;
Console.WriteLine("task creates a result ...");
return Tuple.Create(result,reminder);
}
static void Main(string[] args)
{
var t1 = new Task>(TaskWithResult,Tuple.Create(8,3));
t1.Start();
Console.WriteLine(t1.Result);
t1.Wait();
Console.ReadKey();
}
定义一个调用TaskWithResult()方法的任务时,要使用泛型类Task