代码改变世界

C#基础:使用Task创建任务

2012-06-18 13:44  海豚座  阅读(8204)  评论(4编辑  收藏  举报

  .NET 4 中 包含了新名称空间System.Threading.Task。它包含的类抽象出了线程的功能。使用Task类创建的任务是后台线程,所以在前台线程全部终止的时候,如果任务还没有全部执行万,就会被被动终止。

启动任务

  怎样启动一个任务?代码中我们首先要添加using System.Threading.Tasks;引用。我们可以使用TaskFactory类或Task类的构造函数和Start()方法。在启动任务时,会创建Task类的一个实例。首先我们看一段代码

using System;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleTask
{
    class Program
    {
        static void Main(string[] args)
        {
            //使用TaskFactory创建一个任务
            TaskFactory tf = new TaskFactory();
            Task t1 = tf.StartNew(NewTask);
            //使用Task类de Factory创建一个任务
            Task t2 = Task.Factory.StartNew(NewTask);
            ///////////////////////////////////////
            Task t3 = new Task(NewTask);
            t3.Start();
            Task t4 = new Task(NewTask, TaskCreationOptions.PreferFairness);
            t4.Start();
            Thread.Sleep(1000);//因为任务是后台线程,所以我们这里阻塞主线程一秒钟来等待任务全部执行完成
        }
        static void NewTask()
        {
            Console.WriteLine("开始一个任务");
            Console.WriteLine("Task id:{0}",Task.CurrentId);
            Console.WriteLine("任务执行完成");
        }
    }
}

运行结果:

  在上面代码中。我们可以看到启动新任务的不同方式:

  1、  第一种使用实例化的TaskFactory类,把NewTask()方法传递给StartNew()方法,任务就会立即启动。

  2、  第二种方式是使用Task类的构造函数,实例化任务时,任务不会立即启动,此时任务的状态为Created。然后调用Task类的Start()方法来启动任务,还可以调用RunSynchronously()方法来启动任务。

默认情况下,任务是异步运行的。。。

  使用Task类的构造函数和TaskFactory类的StartNew()方法时,都可以传递TaskCreationOptions枚举中的值。

成员名称

说明

None

指定应使用默认行为。

PreferFairness

提示 TaskScheduler 以一种尽可能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。

LongRunning

指定某个任务将是运行时间长、粗粒度的操作。 它会向 TaskScheduler 提示,过度订阅可能是合理的。

AttachedToParent

指定将任务附加到任务层次结构中的某个父级。

 

  注:摘录至MSDN:http://technet.microsoft.com/zh-CN/library/system.threading.tasks.taskcreationoptions

 

  例如:如果任务使用子任务创建了其它任务,子任务就优先于其它任务。当然它们不会排在线程池的最后。如果这些任务应以公平的方式与所有其它任务一起处理,就设置选项为PerferFainress,如下所示

Task t4 = new Task(NewTask,TaskCreationOptions.PreferFairness);
t4.Start();

 

创建连续的任务

  通过创建任务,我们可以指定在一个任务完成过后,开始运行另外一个指定的任务。任务处理程序不带参数或者带一个Object类型的参数。连续处理程序有一个Task类型的参数,可以访问起始任务的相关信息。

using System;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleContinueTask
{
    class Program
    {
        static void Main(string[] args)
        {
            Task t1 = new Task(FirstTask);
            Task t2 = t1.ContinueWith(SecondTask);
            t1.Start();
            Thread.Sleep(7000);
        }
        static void FirstTask()
        {
            Console.WriteLine("第一个任务开始:TaskID:{0}",Task.CurrentId);
            Thread.Sleep(3000);
        }
        static void SecondTask(Task task)
        {
            Console.WriteLine("任务{0}完成",task.Id);
            Console.WriteLine("第二个任务开始:TaskID:{0}",Task.CurrentId);
            Console.WriteLine("清理工作......");
            Thread.Sleep(3000);
        }
    }

}

  运行结果:

  

 

  连续的任务通过在任务上调用ContinueWith()方法来定义。t1.ContinueWith(SecondTask)方法表示,调用SecondTask()方法的新任务应该在t1任务完成后立即启动过,在第一个任务结束时,还可以启动多个任务。无论前一个任务是如何结束的,前面的连续任务总是在前面一个任务结束时启动,使用TaskContinueOptions枚举中的值可以指定连续任务只有在起始任务成功或者失败时启动,TaskContinueOptions的枚举值有

成员名称

说明

None

Default = "Continue on any, no task options, run asynchronously" 指定应使用默认行为。 默认情况下,完成前面的任务之后将安排运行延续任务,而不考虑前面任务的最终 TaskStatus

PreferFairness

提示 TaskScheduler 以一种尽可能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。

LongRunning

指定某个任务将是运行时间长、粗粒度的操作。 它会向 TaskScheduler 提示,过度订阅可能是合理的。

AttachedToParent

指定将任务附加到任务层次结构中的某个父级。

NotOnRanToCompletion

指定不应在延续任务前面的任务已完成运行的情况下安排延续任务。 此选项对多任务延续无效。

NotOnFaulted

指定不应在延续任务前面的任务引发了未处理异常的情况下安排延续任务。 此选项对多任务延续无效。

NotOnCanceled

指定不应在延续任务前面的任务已取消的情况下安排延续任务。 此选项对多任务延续无效。

OnlyOnRanToCompletion

指定只应在延续任务前面的任务已完成运行的情况下才安排延续任务。 此选项对多任务延续无效。

OnlyOnFaulted

指定只应在延续任务前面的任务引发了未处理异常的情况下才安排延续任务。 此选项对多任务延续无效。

OnlyOnCanceled

指定只应在延续任务前面的任务已取消的情况下才安排延续任务。 此选项对多任务延续无效。

ExecuteSynchronously

指定应同步执行延续任务。 指定此选项后,延续任务将在导致前面的任务转换为其最终状态的相同线程上运行。 如果在创建延续任务时已经完成前面的任务,则延续任务将在创建此延续任务的线程上运行。 只应同步执行运行时间非常短的延续任务。

  摘录至MSDN:http://technet.microsoft.com/zh-CN/library/system.threading.tasks.taskcontinuationoptions

 

 

任务的层次结构

  利用任务的连续性,就可以在一个任务结束后启动另外一个任务。一个任务启动一个新任务时,就启动了一个父/子层次结构,如下所示:

using System;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleLayer
{
    class Program
    {
        static void Main(string[] args)
        {
            Task parent = new Task(ParentTask);
            parent.Start();
            Thread.Sleep(1000);
            Console.WriteLine("父任务的状态:{0}",parent.Status);
            Thread.Sleep(4000);
            Console.WriteLine("父任务的状态:{0}",parent.Status);
        }
        public static void ParentTask()
        {
            Console.WriteLine("父任务{0}正在运行......",Task.CurrentId);
            Task child = new Task(ChildTask);
            child.Start();
            Console.WriteLine("父任务启动了子任务");
            Thread.Sleep(1000);
        }
        static void ChildTask()
        {
            Console.WriteLine("子任务{0}正在运行......",Task.CurrentId);
            Thread.Sleep(3000);
            Console.WriteLine("子任务执行完成。");
        }
    }
}

运行结果:

  

  如果父任务在子任务之前结束,父任务的状态就会显示为WatingForChildrenToComplete。子任务的任务完成后,父任务的状态就是RanToCompletion。