当前位置:编程学习 > C#> 正文

C# Task实现多线程

时间:2015-10-21类别:编程学习

C# Task实现多线程

C# Task实现多线程

一、Task 的优点以及功能

1、在任务启动后,可以随时以任务延续的形式注册回调。

2、通过使用 ContinueWhenAll 和 ContinueWhenAny 方法或者 WaitAll 方法或 WaitAny 方法,协调多个为了响应 Begin_ 方法而执行的操作。

3、在同一Task 对象中封装异步 I/O 绑定和计算绑定操作。

4、监视Task 对象的状态。

5、使用TaskCompletionSource 将操作的状态封送到Task 对象。

 

二、创建 Task

 

1、使用构造函数创建

使用Task的构造函数来创建任务,并调用Start方法来启动任务并执行异步操作。

例如

  •  
  • 
    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);
    
             }
    
    		
  •  

    2、使用Task.Factory.StartNew 进行创建Task

    Task.Factory 是对Task进行管理,调度管理这一类的。

    例如

  •  
  • 
    var task1 = Task.Factory.StartNew(() => DoSomeWork()).ContinueWith(
                      task => { Console.WriteLine(task.Result.ToString()); }).ContinueWith(
                      task => { Console.WriteLine(task.Result.ToString()); });
    
    		
  •  

    三、等待任务的完成并获取返回值

    使用任务执行异步操作时,最主要的是要后的任务完成时的返回值。在任务类中有一个实例方法Wait(有许多重载版本)他能等待任务的完成,我们也可以通过Task类的派生类Task<TResult>创建一个异步任务,并指定任务完成时返回值的类型,这样可以通过Task<TResult>的实例对象获取到任务完成后的返回值。

    例如

  •  
  • 
    static void TaskWait() {
           //创建任务
           Task<int> task = new Task<int>(() =>
           {
               int sum = 0;
               Console.WriteLine("使用Task执行异步操作.");
               for (int i = 0; i < 100; i++)
               {
                   sum+=i;
               }
               return sum;
           });
           //启动任务,并安排到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
           task.Start();
     
           Console.WriteLine("主线程执行其他处理");
           //等待任务的完成执行过程。
           task.Wait();
           //获得任务的执行结果
           Console.WriteLine("任务执行结果:{0}", task.Result.ToString());
    }
    
    		
  •  

    四、等待所有线程结束

  •  
  • 
     var task1 = Task.Factory.StartNew(() => DoSomeWork());
     var task2 = Task.Factory.StartNew(() => DoSomeWork());
     var task3 = Task.Factory.StartNew(() => DoSomeWork());
     Task.WaitAll(task1, task2, task3);
    
    		
  •  

    五、等待其中一个线程结束

     

  •  
     var task1 = Task.Factory.StartNew(() => DoSomeWork());
     var task2 = Task.Factory.StartNew(() => DoSomeWork());
     var task3 = Task.Factory.StartNew(() => DoSomeWork());
     Task.WaitAny(task1, task2, task3);
    
    		
  •  

    六、使用ContinueWith方法在任务完成时启动一个新任务

    在使用能够Task类的Wait方法等待一个任务时或派生类的Result属性获得任务执行结果都有可能阻塞线程,为了解决这个问题可以使用ContinueWith方法,他能在一个任务完成时自动启动一个新的任务来处理执行结果。

  •  
  • 
    static void TaskContinueWith()
    {
        //创建一个任务
        Task<int> task = new Task<int>(() =>
        {
              int sum = 0;
              Console.WriteLine("使用Task执行异步操作.");
              for (int i = 0; i < 100; i++)
              {
                  sum += i;
              }
              return sum;
        });
        //启动任务,并安排到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
        task.Start();
        Console.WriteLine("主线程执行其他处理");
        //任务完成时执行处理。
        Task cwt = task.ContinueWith(t => { 
             Console.WriteLine("任务完成后的执行结果:{0}", t.Result.ToString()); 
        });
        Thread.Sleep(1000);
    }
    
    		
  •  

    七、创建一组具有相同状态的任务

    可以使用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();
    }
    
    		
  •  

    八、任务内部实现和任务调度

     

    1、任务内部有一组构成任务状态的属性,标识任务的唯一Id、表示任务的执行状态(TaskStatus)、任务创建时提供的回调函数的引用和传递给回调函数的数据对象AsyncState、对任务创建时的任务调度对象(TaskScheduler)的引用、对父任务的引用以及对执行上下文的引用和ManualResetEventSlim对象的引用。

    2、Task类和Task<TResult>类都实现了标准的释放资源的接口,允许在任务完成处理的时候使用Dispose方法释放资源(关闭ManualResetEventSlim对象实例)。

    3、可以使用Task类的CurrentId属性获得正在执行的任务的Id,如果没有任务在执行CurrentId返回值为null,CurrentId是一个int?可空类型的属性。

    4、任务执行的生命周期通过TaskStatus类型的一个值来表示,TaskStatus所包含的值:

     

  • 
    public enum TaskStatus
    {
         Created = 0,
         WaitingForActivation = 1,
         WaitingToRun = 2,
         Running = 3,
         WaitingForChildrenToComplete = 4,
         RanToCompletion = 5,
         Canceled = 6,
         Faulted = 7,
    }
    
    		
  • 5、在任务内部由TaskScheduler类调度任务的执行,该类是一个抽象类,FCL中从他派生了两个派生类:

    ThreadPoolTaskScheduler线程池任务调度器

    所有任务默认都是采用ThreadPoolTaskScheduler调度任务,他是采用线程池来执行任务,可以通过TaskScheduler类的静态属性Default获得对默认任务调度器的引用。

    SynchronizationContextTaskScheduler同步上下文任务调度器

    SynchronizationContextTaskScheduler任务调度器能够用在Window form、WPF等应用程序,他的任务调度是采用的GUI线程,所以他能同步更新UI组件,可以通过TaskScheduler类的静态方法FromCurrentSynchronizationContext获得对一个同步上下文任务调度起的引用。

    6、例如

     

  • 
    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();
            }
    
    		
  •  

    标签:
    上一篇下一篇

    猜您喜欢

    热门推荐