首頁 > 軟體

C#多執行緒程式設計Task用法詳解

2022-03-20 19:00:26

一、基本概念

Task優勢

ThreadPool相比Thread來說具備了很多優勢,但是ThreadPool卻又存在一些使用上的不方便,例如:

  • ThreadPool不支援執行緒的取消、完成、失敗通知等互動性操作;
  • ThreadPool不支援執行緒執行的先後次序;

.NET Framework 在4.0的時候提供了一個功能更強大的概念:Task。Task在ThreadPool的基礎上進行了優化,並提供了更多的API。看下面一個簡單的範例:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 建立Task
            Task t = new Task(() => 
            {
                Console.WriteLine("任務開始工作.....");
                Thread.Sleep(5000);
            });
            // 啟動
            t.Start();
            t.ContinueWith((task) => 
            {
                Console.WriteLine("任務完成,完成時候的狀態為:");
                Console.WriteLine("IsCanceled={0}tIsCompleted={1}tIsFaulted={2}", task.IsCanceled, task.IsCompleted, task.IsFaulted);
            });
            Console.WriteLine("啟動");
            Console.ReadKey();
        }
    }
}

二、Task用法

建立任務

Task建立的任務可以分為有返回值和無返回值兩種。

1、使用Task建立無返回值

先看一下Task的定義:

可以看到Task建構函式的引數是Action委託。所以使用Task建立任務的程式碼如下:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task建立任務
            Task task = new Task(() => TaskMethod("Task 1"));
            Console.WriteLine("before start status:"+task.Status);
            // Task建立的任務必須呼叫start方法才能啟動
            task.Start();
            Console.WriteLine("after start status:" + task.Status);
            #endregion
            Console.ReadKey();
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }
    }
}

程式執行結果:

注:任務的狀態,Start之前為Created,Start之後為WaitingToRun。

2、使用Task.Run方法建立任務

Task.Run建立的任務可以執行啟動:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task建立任務
            //Task task = new Task(() => TaskMethod("Task 1"));
            //Console.WriteLine("before start status:"+task.Status);
            //// Task建立的任務必須呼叫start方法才能啟動
            //task.Start();
            //Console.WriteLine("after start status:" + task.Status);
            #endregion

            #region 2、使用Task.Run建立任務
            Task.Run(() => TaskMethod("Task Run"));
            #endregion
            Console.ReadKey();
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }
    }
}

程式執行結果:

3、使用Factory方式建立任務

using System;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task建立任務
            //Task task = new Task(() => TaskMethod("Task 1"));
            //Console.WriteLine("before start status:"+task.Status);
            //// Task建立的任務必須呼叫start方法才能啟動
            //task.Start();
            //Console.WriteLine("after start status:" + task.Status);
            #endregion

            #region 2、使用Task.Run建立任務
            // Task.Run(() => TaskMethod("Task Run"));
            #endregion

            #region 3、使用Factory建立任務
            // 使用Task.Factory建立
            Task.Factory.StartNew(() => TaskMethod("Task 4"));
            //標記為長時間執行任務,則任務不會使用執行緒池,而在單獨的執行緒中執行。
            Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);

            // 範例化TaskFactory物件,然後建立
            TaskFactory factory = new TaskFactory();
            factory.StartNew(() => TaskMethod("Task 6"));


            #endregion
            Console.ReadKey();
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }
    }
}

程式執行結果:

4、建立帶返回值的Task

程式碼如下:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task建立任務
            //Task task = new Task(() => TaskMethod("Task 1"));
            //Console.WriteLine("before start status:"+task.Status);
            //// Task建立的任務必須呼叫start方法才能啟動
            //task.Start();
            //Console.WriteLine("after start status:" + task.Status);
            #endregion

            #region 2、使用Task.Run建立任務
            // Task.Run(() => TaskMethod("Task Run"));
            #endregion

            #region 3、使用Task.Factory建立任務
            //Task.Factory.StartNew(() => TaskMethod("Task 4"));
            ////標記為長時間執行任務,則任務不會使用執行緒池,而在單獨的執行緒中執行。
            //Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);
            #endregion

            #region 4、建立帶返回值的任務
            TaskMethodReturn("Main Thread Task");
            // 建立帶返回值的Task
            Task<int> task = CreateTask("Task 1");
            // 啟動
            task.Start();
            // 獲取返回值
            int result1 = task.Result;
            Console.WriteLine($"Task 1 Result is:{result1}");
            Task<int> task2 = new Task<int>(() => TaskMethodReturn("Task 2"));
            task2.Start();
            int result2 = task2.Result;
            Console.WriteLine($"Task 2 Result is:{result2}");
            int result3= Task.Run<int>(() => TaskMethodReturn("Task 3")).Result;
            Console.WriteLine($"Task 3 Result is:{result3}");
            int result4 = Task.Factory.StartNew<int>(() => TaskMethodReturn("Task 4")).Result;
            Console.WriteLine($"Task 4 Result is:{result4}");
            #endregion
            Console.ReadKey();
        }

        /// <summary>
        /// 返回一個Task<int>
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        static Task<int> CreateTask(string name)
        {
            // 引數是Func<int>
            return new Task<int>(() => TaskMethodReturn(name));
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }

        static int TaskMethodReturn(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                   name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(TimeSpan.FromSeconds(2));
            return 42;
        }
    }
}

程式執行結果:

我們在文章開始的時候說過,Task是基於ThreadPool的,那麼怎麼證明呢?看下面的程式碼:

/// <summary>
/// 測試Task的執行緒來自於ThreadPool
/// </summary>
static void Test()
{
            // 設定執行緒池中最大的執行緒數
            ThreadPool.SetMaxThreads(6, 6);
            // 建立Task的集合
            List<Task> taskList = new List<Task>();
            // 建立int型別的集合,用於存放執行緒ID
            List<int> threadIdList = new List<int>();
            // 使用Task迴圈建立50個執行緒
            for (int i = 0; i < 30; i++)
            {
                int k = i;
                Task task = Task.Run(() => 
                {
                    // 當前執行緒ID加入到集合中
                    threadIdList.Add(Thread.CurrentThread.ManagedThreadId);
                    Console.WriteLine($"this is {k} 迴圈 ThreadID:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    // 休眠
                    Thread.Sleep(200);
                });
                // 把task加入到集合中
                taskList.Add(task);
            }

            // 等待所有的執行緒執行完
            Task.WaitAll(taskList.ToArray());
            // 輸出總數量
            Console.WriteLine($"執行緒總數:{threadIdList.Distinct().Count()}");
}

程式執行結果:

從結果中可以看出,Task中的執行緒確實是來自於ThreadPool。

三、常見方法

我們以下面的一個例子來講解Task中比較常見的幾個方法。多名開發者合作開發一個專案,每個人負責一個模組的開發,我們可以把這個過程認為是多執行緒,程式碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task建立任務
            //Task task = new Task(() => TaskMethod("Task 1"));
            //Console.WriteLine("before start status:"+task.Status);
            //// Task建立的任務必須呼叫start方法才能啟動
            //task.Start();
            //Console.WriteLine("after start status:" + task.Status);
            #endregion

            #region 2、使用Task.Run建立任務
            // Task.Run(() => TaskMethod("Task Run"));
            #endregion

            #region 3、使用Factory建立任務
            // 使用Task.Factory建立
            //Task.Factory.StartNew(() => TaskMethod("Task 4"));
            ////標記為長時間執行任務,則任務不會使用執行緒池,而在單獨的執行緒中執行。
            //Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);

            // 範例化TaskFactory物件,然後建立
            //TaskFactory factory = new TaskFactory();
            //factory.StartNew(() => TaskMethod("Task 6"));
            #endregion

            #region 4、建立帶返回值的任務
            //TaskMethodReturn("Main Thread Task");
            //// 建立帶返回值的Task
            //Task<int> task = CreateTask("Task 1");
            //// 啟動
            //task.Start();
            //// 獲取返回值
            //int result1 = task.Result;
            //Console.WriteLine($"Task 1 Result is:{result1}");
            //Task<int> task2 = new Task<int>(() => TaskMethodReturn("Task 2"));
            //task2.Start();
            //int result2 = task2.Result;
            //Console.WriteLine($"Task 2 Result is:{result2}");
            //int result3= Task.Run<int>(() => TaskMethodReturn("Task 3")).Result;
            //Console.WriteLine($"Task 3 Result is:{result3}");
            //int result4 = Task.Factory.StartNew<int>(() => TaskMethodReturn("Task 4")).Result;
            //Console.WriteLine($"Task 4 Result is:{result4}");
            #endregion


            #region 測試Task執行緒是來自於ThreadPool

            // Test();
            #endregion

            // 合作開發專案,每個人負責一個模組,可以認為是多執行緒
            Console.WriteLine("開始合作開發一個大專案!");
            Task.Run(() => CodingShow("Tom", "搭建微服務架構!"));
            Task.Run(() => CodingShow("Kevin", "微信介面!"));
            Task.Run(() => CodingShow("Jack", "搭建後臺框架!"));
            Task.Run(() => CodingShow("Alex", "設計資料庫!"));
            Task.Run(() => CodingShow("Lee", "支付寶介面對接!"));





            Console.ReadKey();
        }

        /// <summary>
        /// 返回一個Task<int>
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        static Task<int> CreateTask(string name)
        {
            // 引數是Func<int>
            return new Task<int>(() => TaskMethodReturn(name));
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }

        static int TaskMethodReturn(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                   name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(TimeSpan.FromSeconds(2));
            return 42;
        }

        /// <summary>
        /// 測試Task的執行緒來自於ThreadPool
        /// </summary>
        static void Test()
        {
            // 設定執行緒池中最大的執行緒數
            ThreadPool.SetMaxThreads(6, 6);
            // 建立Task的集合
            List<Task> taskList = new List<Task>();
            // 建立int型別的集合,用於存放執行緒ID
            List<int> threadIdList = new List<int>();
            // 使用Task迴圈建立50個執行緒
            for (int i = 0; i < 30; i++)
            {
                int k = i;
                Task task = Task.Run(() =>
                {
                    // 當前執行緒ID加入到集合中
                    threadIdList.Add(Thread.CurrentThread.ManagedThreadId);
                    Console.WriteLine($"this is {k} 迴圈 ThreadID:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    // 休眠
                    Thread.Sleep(200);
                });
                // 把task加入到集合中
                taskList.Add(task);
            }

            // 等待所有的執行緒執行完
            Task.WaitAll(taskList.ToArray());
            // 輸出總數量
            Console.WriteLine($"執行緒總數:{threadIdList.Distinct().Count()}");
        }

        /// <summary>
        /// 模擬Coding過程
        /// </summary>
        /// <param name="name"></param>
        /// <param name="projectName"></param>
        static void CodingShow(string name, string projectName)
        {
            Console.WriteLine($"CodingShow Start  {name} {projectName}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
            long lResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                lResult += i;
            }

            Console.WriteLine($"CodingShow   End  {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
        }
    }
}

程式執行結果:

這時需求發生了變化,所有的模組都開發完成以後,開始搭建測試環境,修改程式碼如下:

// 合作開發專案,每個人負責一個模組,可以認為是多執行緒
Console.WriteLine("開始合作開發一個大專案!");
Task.Run(() => CodingShow("Tom", "搭建微服務架構!"));
Task.Run(() => CodingShow("Kevin", "微信介面!"));
Task.Run(() => CodingShow("Jack", "搭建後臺框架!"));
Task.Run(() => CodingShow("Alex", "設計資料庫!"));
Task.Run(() => CodingShow("Lee", "支付寶介面對接!"));
Console.WriteLine("所有模組都開發完成,開始搭建測試環境");

程式執行結果:

可以看到顯然不是我們想要的結果,模組開發工作還沒有結束就搭建測試環境,即子執行緒還沒有結束,主執行緒就已經結束了。要想實現我們想要的效果,那麼必須使主執行緒等待所有子執行緒都結束以後,主執行緒才能結束。

1、WaitAll()

WaitAll()表示等待所有的Task都執行完成。看WaitAll()的定義:

WaitAll()方法有很多過載,我們在這裡使用第一個過載方法,即引數是Task[]陣列。檢視Run()方法的定義時,我們會發現Run()方法的返回值就是Task型別,我們使用WaitAll()修改上面的程式碼:

// 定義一個Task型別的集合
List<Task> taskList = new List<Task>();
Console.WriteLine("開始合作開發一個大專案!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務架構!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信介面!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建後臺框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "設計資料庫!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶介面對接!")));

// 等待所有模組都開發完成,才能搭建測試環境
Task.WaitAll(taskList.ToArray());
Console.WriteLine("所有模組都開發完成,開始搭建測試環境");

程式執行結果:

WaitAll()會使程式產生卡頓。

載入首頁資訊的時候可以使用WaitAll()方法。一個首頁資訊可能來自於幾部分的資料,每一部分的資料對應一個執行緒,只有所有的執行緒都執行完畢才顯示首頁資訊。

2、WaitAny()

這時需求又發生改變了:某一個模組開發完成以後就搭建測試環境。這時候就可以使用WaitAny()了。WaitAny()表示等待其中任何一個任務完成就會進入下一個任務,定義如下:

修改後的程式碼如下:

// 定義一個Task型別的集合
List<Task> taskList = new List<Task>();
Console.WriteLine("開始合作開發一個大專案!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務架構!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信介面!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建後臺框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "設計資料庫!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶介面對接!")));

// 等待所有模組都開發完成,才能搭建測試環境
Task.WaitAny(taskList.ToArray());
Console.WriteLine("有模組開發完成,開始搭建測試環境");

程式執行結果:

可以看到:設計資料庫模組完成以後,就開始搭建測試環境了。如何需求。

WaitAny()會使程式產生卡頓。

有一個列表資料,資料可以來源於介面、快取、資料庫等,可以開啟多個執行緒,只要有一個執行緒執行完畢就可以繼續執行下面的步驟,這時就可以使用WaitAny()。

3、ContinueWhenAll()

WaitAll()會卡頓介面,那麼有沒有不卡頓介面的呢?ContinueWhenAll和WaitAll實現的效果一樣,程式碼如下:

List<Task> taskList = new List<Task>();
Console.WriteLine("開始合作開發一個大專案!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務架構!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信介面!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建後臺框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "設計資料庫!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶介面對接!")));
TaskFactory factory = new TaskFactory();
factory.ContinueWhenAll(taskList.ToArray(), t => Console.WriteLine("所有模組開發完成"));

程式執行結果:

4、ContinueWhenAny

ContinueWhenAny實現的效果和WaitAny一樣,ContinueWhenAny不會卡頓介面,程式碼如下:

List<Task> taskList = new List<Task>();
Console.WriteLine("開始合作開發一個大專案!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務架構!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信介面!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建後臺框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "設計資料庫!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶介面對接!")));
TaskFactory factory = new TaskFactory();
factory.ContinueWhenAny(taskList.ToArray(), t => Console.WriteLine("某一個模組開發完成"));

程式執行結果:

ContinueWhenAll()和ContinueWhenAny()都會開啟一個新的執行緒。

5、ContinueWith

ContinueWith表示回撥,程式碼如下:

Task.Run(() => { Console.WriteLine("任務執行完成"); }).ContinueWith(p=> 
{
      Task.Run(() => { Console.WriteLine("執行回撥"); });
});

程式執行結果:

程式完整程式碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task建立任務
            //Task task = new Task(() => TaskMethod("Task 1"));
            //Console.WriteLine("before start status:"+task.Status);
            //// Task建立的任務必須呼叫start方法才能啟動
            //task.Start();
            //Console.WriteLine("after start status:" + task.Status);
            #endregion

            #region 2、使用Task.Run建立任務
            // Task.Run(() => TaskMethod("Task Run"));
            #endregion

            #region 3、使用Factory建立任務
            // 使用Task.Factory建立
            //Task.Factory.StartNew(() => TaskMethod("Task 4"));
            ////標記為長時間執行任務,則任務不會使用執行緒池,而在單獨的執行緒中執行。
            //Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);

            // 範例化TaskFactory物件,然後建立
            //TaskFactory factory = new TaskFactory();
            //factory.StartNew(() => TaskMethod("Task 6"));
            #endregion

            #region 4、建立帶返回值的任務
            //TaskMethodReturn("Main Thread Task");
            //// 建立帶返回值的Task
            //Task<int> task = CreateTask("Task 1");
            //// 啟動
            //task.Start();
            //// 獲取返回值
            //int result1 = task.Result;
            //Console.WriteLine($"Task 1 Result is:{result1}");
            //Task<int> task2 = new Task<int>(() => TaskMethodReturn("Task 2"));
            //task2.Start();
            //int result2 = task2.Result;
            //Console.WriteLine($"Task 2 Result is:{result2}");
            //int result3= Task.Run<int>(() => TaskMethodReturn("Task 3")).Result;
            //Console.WriteLine($"Task 3 Result is:{result3}");
            //int result4 = Task.Factory.StartNew<int>(() => TaskMethodReturn("Task 4")).Result;
            //Console.WriteLine($"Task 4 Result is:{result4}");
            #endregion


            #region 測試Task執行緒是來自於ThreadPool

            // Test();
            #endregion

            // 合作開發專案,每個人負責一個模組,可以認為是多執行緒
            // 無序
            //Console.WriteLine("開始合作開發一個大專案!");
            //Task.Run(() => CodingShow("Tom", "搭建微服務架構!"));
            //Task.Run(() => CodingShow("Kevin", "微信介面!"));
            //Task.Run(() => CodingShow("Jack", "搭建後臺框架!"));
            //Task.Run(() => CodingShow("Alex", "設計資料庫!"));
            //Task.Run(() => CodingShow("Lee", "支付寶介面對接!"));
            //Console.WriteLine("所有模組都開發完成,開始搭建測試環境");

            #region WaitAll
            //// 定義一個Task型別的集合
            //List<Task> taskList = new List<Task>();
            //Console.WriteLine("開始合作開發一個大專案!");
            //taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務架構!")));
            //taskList.Add(Task.Run(() => CodingShow("Kevin", "微信介面!")));
            //taskList.Add(Task.Run(() => CodingShow("Jack", "搭建後臺框架!")));
            //taskList.Add(Task.Run(() => CodingShow("Alex", "設計資料庫!")));
            //taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶介面對接!")));

            //// 等待所有模組都開發完成,才能搭建測試環境
            //Task.WaitAll(taskList.ToArray());
            //Console.WriteLine("所有模組都開發完成,開始搭建測試環境");
            #endregion

            #region WaitAny
            // 定義一個Task型別的集合
            //List<Task> taskList = new List<Task>();
            //Console.WriteLine("開始合作開發一個大專案!");
            //taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務架構!")));
            //taskList.Add(Task.Run(() => CodingShow("Kevin", "微信介面!")));
            //taskList.Add(Task.Run(() => CodingShow("Jack", "搭建後臺框架!")));
            //taskList.Add(Task.Run(() => CodingShow("Alex", "設計資料庫!")));
            //taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶介面對接!")));

            //// 等待所有模組都開發完成,才能搭建測試環境
            //Task.WaitAny(taskList.ToArray());
            //Console.WriteLine("有模組開發完成,開始搭建測試環境");
            #endregion

            #region ContinueWhenAll
            //List<Task> taskList = new List<Task>();
            //Console.WriteLine("開始合作開發一個大專案!");
            //taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務架構!")));
            //taskList.Add(Task.Run(() => CodingShow("Kevin", "微信介面!")));
            //taskList.Add(Task.Run(() => CodingShow("Jack", "搭建後臺框架!")));
            //taskList.Add(Task.Run(() => CodingShow("Alex", "設計資料庫!")));
            //taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶介面對接!")));
            //TaskFactory factory = new TaskFactory();
            //factory.ContinueWhenAll(taskList.ToArray(), t => Console.WriteLine("所有模組開發完成"));
            #endregion

            #region ContinueWhenAll
            //List<Task> taskList = new List<Task>();
            //Console.WriteLine("開始合作開發一個大專案!");
            //taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務架構!")));
            //taskList.Add(Task.Run(() => CodingShow("Kevin", "微信介面!")));
            //taskList.Add(Task.Run(() => CodingShow("Jack", "搭建後臺框架!")));
            //taskList.Add(Task.Run(() => CodingShow("Alex", "設計資料庫!")));
            //taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶介面對接!")));
            //TaskFactory factory = new TaskFactory();
            //factory.ContinueWhenAny(taskList.ToArray(), t => Console.WriteLine("某一個模組開發完成"));
            #endregion

            #region ContinueWith
            Task.Run(() => { Console.WriteLine("任務執行完成"); }).ContinueWith(p=> 
            {
               Task.Run(() => { Console.WriteLine("執行回撥"); });
            });
            #endregion



            Console.ReadKey();
        }

        /// <summary>
        /// 返回一個Task<int>
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        static Task<int> CreateTask(string name)
        {
            // 引數是Func<int>
            return new Task<int>(() => TaskMethodReturn(name));
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }

        static int TaskMethodReturn(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                   name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(TimeSpan.FromSeconds(2));
            return 42;
        }

        /// <summary>
        /// 測試Task的執行緒來自於ThreadPool
        /// </summary>
        static void Test()
        {
            // 設定執行緒池中最大的執行緒數
            ThreadPool.SetMaxThreads(6, 6);
            // 建立Task的集合
            List<Task> taskList = new List<Task>();
            // 建立int型別的集合,用於存放執行緒ID
            List<int> threadIdList = new List<int>();
            // 使用Task迴圈建立50個執行緒
            for (int i = 0; i < 30; i++)
            {
                int k = i;
                Task task = Task.Run(() =>
                {
                    // 當前執行緒ID加入到集合中
                    threadIdList.Add(Thread.CurrentThread.ManagedThreadId);
                    Console.WriteLine($"this is {k} 迴圈 ThreadID:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    // 休眠
                    Thread.Sleep(200);
                });
                // 把task加入到集合中
                taskList.Add(task);
            }

            // 等待所有的執行緒執行完
            Task.WaitAll(taskList.ToArray());
            // 輸出總數量
            Console.WriteLine($"執行緒總數:{threadIdList.Distinct().Count()}");
        }

        /// <summary>
        /// 模擬Coding過程
        /// </summary>
        /// <param name="name"></param>
        /// <param name="projectName"></param>
        static void CodingShow(string name, string projectName)
        {
            Console.WriteLine($"CodingShow Start  {name} {projectName}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
            long lResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                lResult += i;
            }

            Console.WriteLine($"CodingShow   End  {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
        }
    }
}

到此這篇關於C#多執行緒程式設計Task用法的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com