C# 使用Task執行異步操做

  1. 爲何要使用 Task
  2. Task 和 Thread 區別
  3. Task 介紹
  4. Task 簡單實現
  5. Task 執行狀態

爲何要使用 Task

線程是建立併發的底層工具,所以具備必定的侷限性。html

  • 沒有簡單的方法能夠從聯合(Join)線程獲得「返回值」。所以必須建立一些共享域。當拋出一個異常時,捕捉和處理異常也是麻煩的。
  • 線程完成以後,沒法再次啓動該線程。相反,只能聯合(Join)它(在進程阻塞當前線程)。

任務是可組合的——使用延續將它們串聯在一塊兒。它們可使用線程池減小啓動延遲,並且它們能夠經過TaskCompletionSource使用回調方法,避免多個線程同時等待I/O密集操做。架構

Task 和 Thread 區別

一、任務是架構在線程之上的,也就是說任務最終仍是要拋給線程去執行。併發

二、任務跟線程不是一對一的關係,好比開10個任務並非說會開10個線程,這一點任務有點相似線程池,可是任務相比線程池有很小的開銷和精確的控制。異步

Task和Thread同樣,位於System.Threading命名空間下函數

 

與線程相比,Task是一個更高級的抽象概念,它標識一個經過或不經過線程實現的併發操做。工具

Task 介紹

Task 類的表示單個操做不返回一個值,一般以異步方式執行。 Task 對象是一個的中心思想 基於任務的異步模式 首次引入.NET Framework 4 中。 由於由執行工做 Task 對象一般以異步方式執行在線程池線程上而不是以同步方式在主應用程序線程,您可使用 Status 屬性,以及 IsCanceled, ,IsCompleted, ,和 IsFaulted 屬性,以肯定任務的狀態。 大多數狀況下,lambda 表達式用於指定的任務是執行的工做。spa

Task 簡單實現

經過使用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);
            }
      });
     //啓動任務,並安排到當前任務隊列線程中執行任務
      task.Start();
      Console.WriteLine("主線程執行其餘處理");
}

 

從Framework 4.5開始,啓動一個由後臺線程實現的Task,也可使用靜態方法 Task.Run代理

Task task = Task.Run(() =>
    {
        Thread.Sleep(2000);
        Console.WriteLine("Foo");
    });

 

 

Task默認使用線程池,它們都是後臺線程。意味當主線程結束時,全部任務都會隨之中止。

 

Task 執行狀態

1.等待(Wait)

調用Wait方法,能夠阻塞任務,直至任務完成,效果等同於Thread.Joincode

    Task task = Task.Run(() =>
    {
        Thread.Sleep(2000);
        Console.WriteLine("Foo");
    });
    Console.WriteLine(task.IsCompleted); //False
    task.Wait();//阻塞,直至任務完成
    Console.WriteLine(task.IsCompleted); //True
    Console.ReadLine();

2. 返回值

Task<TResult>容許任務返回一個值。調用Task.Run,傳入一個Func<TResult>代理(或者兼容的Lambda表達式),代替Action,就能夠得到一個Task<TResult>:

Task<int> task = Task.Run (() => { Console.WriteLine ("Foo"); return 3; });

int result = task.Result;      // Blocks if not already finished
Console.WriteLine (result);    // 3

 

下面的例子建立一個任務,它使用LINQ就按前3百萬個整數(從2開始)中的素數個數:

Task<int> primeNumberTask = Task.Run(() =>
        Enumerable.Range(2, 3000000).Count(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)));

    Console.WriteLine("Task running...");
    Console.WriteLine("The answer is " + primeNumberTask.Result);

這段代碼會打印「Task running...」,而後幾秒鐘後打印216815。

 

3. Task.Delay

Task.DelayThread.Sleep的異步版本

Task.Delay(5000).GetAwaiter().OnCompleted(()=>Console.WriteLine(42));

或者

Task.Delay(5000).ContinueWith(ant => Console.WriteLine(42));

 

 

參考資料:

https://www.jianshu.com/p/4444f2d77f3b

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

相關文章
相關標籤/搜索