C# 线程知识--使用Task执行异步操做

来源:https://www.cnblogs.com/pengstone/archive/2012/12/23/2830238.html      html

 

在C#4.0以前须要执行一个复杂的异步操做时,只能使用CLR线程池技术来执行一个任务。线程池执行异步任务时,不知道任务什么时候完成,以及任务的在任务完成后不能获取到返回值。可是在C#4.0中引人了一个的任务(System.Threading.Tasks命名空间的类型)机制来解决异步操做完成时间和完成后返回值的问题。异步

1.使用Task类建立并执行简单任务函数

    经过使用Task的构造函数来建立任务,并调用Start方法来启动任务并执行异步操做。建立任务时,必须传递一个Action或Action<Object>类型的委托回调方法,能够选择的传递任务执行时说须要的数据对象等。Task类的构造函数以下:this

        public Task(Action action);
        public Task(Action<object> action, object state);
        public Task(Action action, CancellationToken cancellationToken);
        public Task(Action action, TaskCreationOptions creationOptions);
        public Task(Action<object> action, object state, CancellationToken cancellationToken);
        public Task(Action<object> action, object state, TaskCreationOptions creationOptions);
        public Task(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions);
        public Task(Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions);

示例代码:spa

static void Main(string[] args)
        {
            Console.WriteLine("主线程执行业务处理.");
            //建立任务
            Task task = new Task(() => {
                Console.WriteLine("使用System.Threading.Tasks.Task执行异步操做.");
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine(i);
                }
            });
            //启动任务,并安排到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
            task.Start();
            Console.WriteLine("主线程执行其余处理");
            //主线程挂起1000毫秒,等待任务的完成。
            Thread.Sleep(1000);
        }

任务调度结果:image线程

2.等待任务的完成并获取返回值code

     使用任务执行异步操做时,最主要的是要后的任务完成时的返回值。在任务类中有一个实例方法Wait(有许多重载版本)他能等待任务的完成,咱们也能够经过Task类的派生类Task<TResult>建立一个异步任务,并指定任务完成时返回值的类型,这样能够经过Task<TResult>的实例对象获取到任务完成后的返回值。建立一个异步任务并执行0到100求和操做返回最后的计算结果,示例代码:orm

 

执行结果:imagehtm

    若是须要建立一组具备相同状态的任务时,可使用TaskFactory类或TaskFactory<TResult>类。这两个类建立一组任务时能够指定任务的CancellationToken、TaskCreationOptions、TaskContinuationOptions和TaskScheduler默认值。示例代码:对象

 static void TaskFactoryApply()
 {
     Task parent = new Task(() =>
     {
         CancellationTokenSource cts = new CancellationTokenSource(5000);
         //建立任务工厂
         TaskFactory tf = new TaskFactory(cts.Token, TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
         //添加一组具备相同状态的子任务
         Task[] task = new Task[]{
             tf.StartNew(() => { Console.WriteLine("我是任务工厂里的第一个任务。"); }),
             tf.StartNew(() => { Console.WriteLine("我是任务工厂里的第二个任务。"); }),
             tf.StartNew(() => { Console.WriteLine("我是任务工厂里的第三个任务。"); })
         };
     });
     parent.Start();
     Console.Read();
 }

执行结果:image

5.任务内部实现和任务调度

    任务内部有一组构成任务状态的属性,标识任务的惟一Id、表示任务的执行状态(TaskStatus)、任务建立时提供的回调函数的引用和传递给回调函数的数据对象AsyncState、对任务建立时的任务调度对象(TaskScheduler)的引用、对父任务的引用以及对执行上下文的引用和ManualResetEventSlim对象的引用。Task类和Task<TResult>类都实现了标准的释放资源的接口,容许在任务完成处理的时候使用Dispose方法释放资源(关闭ManualResetEventSlim对象实例)。可使用Task类的CurrentId属性得到正在执行的任务的Id,若是没有任务在执行CurrentId返回值为null,CurrentId是一个int?可空类型的属性。任务执行的生命周期经过TaskStatus类型的一个值来表示,TaskStatus所包含的值:

public enum TaskStatus
{
            Created = 0,
            WaitingForActivation = 1,
            WaitingToRun = 2,
            Running = 3,
            WaitingForChildrenToComplete = 4,
            RanToCompletion = 5,
            Canceled = 6,
            Faulted = 7,
}

      咱们能够经过Task类的Exception属性得到任务在执行过程当中的全部异常,Exception是一个AggregateException类型的属性。Task类提供了IsCanceled、IsCompleted、IsFaulted属性来得到任务的完成状态。经过ContinueWith、ContinueWhenAll、ContinueWhenAny和FromAsync建立的后续任务都处于WaitingForActivation 状态,这个状态的任务会在父任务完成后自动执行。

      在任务内部由TaskScheduler类调度任务的执行,该类是一个抽象类,FCL中从他派生了两个派生类:ThreadPoolTaskScheduler线程池任务调度器和SynchronizationContextTaskScheduler同步上下文任务调度器。全部任务默认都是采用ThreadPoolTaskScheduler调度任务,他是采用线程池来执行任务,能够经过TaskScheduler类的静态属性Default得到对默认任务调度器的引用。SynchronizationContextTaskScheduler任务调度器可以用在Window form、WPF等应用程序,他的任务调度是采用的GUI线程,因此他能同步更新UI组件,能够经过TaskScheduler类的静态方法FromCurrentSynchronizationContext得到对一个同步上下文任务调度起的引用。

任务调度示例:

 private void button1_Click(object sender, EventArgs e)
  {
             //得到同步上下文任务调度器
           TaskScheduler m_syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
 
            //建立任务,并采用默认任务调度器(线程池任务调度器)执行任务
            Task<int> task = new Task<int>(() =>
            {
                //执行复杂的计算任务。
                Thread.Sleep(2000);
                int sum = 0;
                for (int i = 0; i < 100; i++)
                {
                    sum += i;
                }
                return sum;
            });
             var cts=new CancellationTokenSource();
            //任务完成时启动一个后续任务,并采用同步上下文任务调度器调度任务更新UI组件。
            task.ContinueWith(t => {this.label1.Text="采用SynchronizationContextTaskScheduler任务调度器更新UI。\r\n计算结果是:"+task.Result.ToString(); },
               cts.Token ,TaskContinuationOptions.AttachedToParent,m_syncContextTaskScheduler);
            task.Start();
 }

 

执行结果:image

    本文简单的介绍了使用Task类来执行异步操做以及任务的内部实现与任务调度。在执行复杂异步操做时,能够采用任务来执行,他能更好的知道异步操做在什么时候完成以及返回异步操做的执行结果。

相关文章
相关标签/搜索