1. 程式人生 > >Task.Run 和 Task.Factory.StartNew 區別

Task.Run 和 Task.Factory.StartNew 區別

Task.Run 是在 dotnet framework 4.5 之後才可以使用, Task.Factory.StartNew 可以使用比 Task.Run 更多的引數,可以做到更多的定製。

可以認為 Task.Run 是簡化的 Task.Factory.StartNew 的使用,除了需要指定一個執行緒是長時間佔用的,否則就使用 Task.Run

建立新執行緒

下面來告訴大家使用兩個函式建立新的執行緒

Task.Run(() =>
{
   var foo = 2;
});

這時 foo 的建立就在另一個執行緒,需要知道 Task.Run 用的是執行緒池,也就是不是呼叫這個函式就會一定建立一個新的執行緒,但是會在另一個執行緒執行。

Task.Factory.StartNew(() =>
{
    ar foo = 2;
});

可以看到,兩個方法實際上是沒有差別,但是Task.Run比較好看,所以推薦使用Task.Run

等待執行緒

建立的執行緒,如果需要等待執行緒執行完成在繼續,那麼可以使用 await 等待

複製程式碼

private static async void SeenereKousa()
{
     Console.WriteLine("開始 執行緒"+Thread.CurrentThread.ManagedThreadId);
     await Task.Run(() =>
     {
         Console.WriteLine("進入 執行緒" + Thread.CurrentThread.ManagedThreadId);
     });
     Console.WriteLine("退出 執行緒"+Thread.CurrentThread.ManagedThreadId);
}

複製程式碼

但是需要說的是這裡使用 await 主要是給函式呼叫的外面使用,上面程式碼在函式裡面使用 await 函式是 void 那麼和把程式碼放在 task 裡面是相同

複製程式碼

private static async void SeenereKousa()
{
    Console.WriteLine("開始 執行緒"+Thread.CurrentThread.ManagedThreadId);
    await Task.Run(() =>
    {
         Console.WriteLine("進入 執行緒" + Thread.CurrentThread.ManagedThreadId);
         Console.WriteLine("退出 執行緒"+Thread.CurrentThread.ManagedThreadId);
    });
}

複製程式碼

但是如果把 void 修改為 Task ,那麼等待執行緒才有用

除了使用 await 等待,還可以使用 WaitAll 等待

複製程式碼

 Console.WriteLine("開始 執行緒" + Thread.CurrentThread.ManagedThreadId);
 var t = Task.Run(() =>
 {
      Console.WriteLine("進入 執行緒" + Thread.CurrentThread.ManagedThreadId);
 });

 Task.WaitAll(t);
 Console.WriteLine("退出 執行緒" + Thread.CurrentThread.ManagedThreadId);

複製程式碼

使用 WaitAll 是在呼叫 WaitAll 的執行緒等待,也就是先線上程 1 執行,然後非同步到 執行緒2 執行,這時執行緒1 等待執行緒2執行完成再繼續,所以輸出

開始 執行緒1
進入 執行緒2
退出 執行緒1

長時間執行

兩個函式最大的不同在於 Task.Factory.StartNew 可以設定執行緒是長時間執行,這時執行緒池就不會等待這個執行緒回收

複製程式碼

Task.Factory.StartNew(() =>
{
      for (int i = 0; i < 100; i++)
      {
           var foo = 2;
      }
      Console.WriteLine("進行 執行緒" + Thread.CurrentThread.ManagedThreadId);
}, TaskCreationOptions.LongRunning);

複製程式碼

所以在需要設定執行緒是長時間執行的才需要使用 Task.Factory.StartNew 不然就使用 Task.Run

呼叫 Task.Run(foo) 就和使用下面程式碼一樣

Task.Factory.StartNew(foo, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);