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類來執行異步操做以及任務的內部實現與任務調度。在執行復雜異步操做時,能夠採用任務來執行,他能更好的知道異步操做在什麼時候完成以及返回異步操做的執行結果。

相關文章
相關標籤/搜索