c# Thread、ThreadPool、Task有什麼區別

https://www.jianshu.com/p/22059d39328e

這三者都是爲了處理耗時任務,都是異步的;

先說 Thread與ThreadPoll

前臺線程:主程序必須等待線程執行完畢後纔可退出程序。Thread默認爲前臺線程,也可以設置爲後臺線程

後臺線程:主程序執行完畢後就退出,不管線程是否執行完畢。ThreadPool默認爲後臺線程

線程消耗:開啓一個新線程,線程不做任何操作,都要消耗1M左右的內存

ThreadPoll是線程池 其目的是爲了減少開啓新線程消耗的資源(使用線程池中的空閒線程,不必在開啓新線程,以及統一管理線程(線程池中的線程執行完畢後,迴歸到線程池裏,等待新任務).

總結:ThreadPoll性能優於Thread,但是Thread和ThreadPoll對線程的控制都不是很好,例如線程等待(線程執行一段時間無響應後,直接停止線程,釋放資源 等 都沒有直接的API來控制 只能通過硬編碼來實現,同時ThreadPool使用的是線程池全局隊列,全局隊列中的線程依舊會存在競爭共享資源的情況,從而影響性能。

然後task

Task的背後的實現也是使用了線程池線程,但它的性能優於ThreadPoll,因爲它使用的不是線程池的全局隊列,而是使用的本地隊列,使線程之間的資源競爭減少。同時Task提供了豐富的API來管理線程、控制。但是相對前面的兩種耗內存,Task依賴於CPU對於多核的CPU性能遠超前兩者,單核的CPU三者的性能沒什麼差別。

下面我們來寫個簡單的代碼

創建Task有兩種方法:

Task t = Task.Factory.StartNew(() => {

                Console.WriteLine("任務已啓動....");

            });

Task t2 = new Task(() => {

                Console.WriteLine("開啓一個新任務");

            });

            t2.Start();//任務已啓動...

第一種方法不需要調用start 初始化後任務就開始了。

Task還可以隨時取消正在執行的任務,請看下面的代碼

static void Main(string[] args)

 {

CancellationTokenSource cts = new CancellationTokenSource();

            Task t3 = new Task(() => LongRunTask(cts.Token));

            t2.Start();

            Thread.Sleep(3000);

            cts.Cancel();

            Console.Read();

}

private static void LongRunTask(CancellationToken token)

        {

            while (true)

            {

                if (!token.IsCancellationRequested)

                {

                    Thread.Sleep(500);

                    Console.WriteLine(".");

                }

                else

                {

                    Console.WriteLine("任務取消了");

                    break;

                }

            }

        }

任務啓動任務  當一個任務完成後 開啓一個新的任務

Task task = new Task(() => { Thread.Sleep(5000); Console.WriteLine("Hello,"); Thread.Sleep(5000); });

            task.Start();

            Task newTask = task.ContinueWith(t => Console.WriteLine("開啓了另一個任務"));

對於ContinueWith方法,我們可以配合TaskContinuationOptions枚舉,得到更多我們想要的行爲。

Task parant = new Task(() =>

            {

                new Task(() => Console.WriteLine("1")).Start();

                new Task(() => Console.WriteLine("2")).Start();

                new Task(() => Console.WriteLine("3")).Start();

                new Task(() => Console.WriteLine("4")).Start();

            });

            parant.Start();

值得注意的是,以上代碼中所示的子任務的調用並不是以代碼的出現先後爲順序來調用的。

任務工廠

在某些情況下,我們會創建大量的任務來滿足業務,而恰好這些任務公用某個狀態參數,爲了避免大量的調用任務的構造器和一次又一次的傳遞參數,我們可以使用任務工廠來處理這種大量的創建任務,如下代碼:

Task parent = new Task(() => 

            { 

                CancellationTokenSource cts = new CancellationTokenSource(); 

                TaskFactory tf = new TaskFactory(cts.Token); 

                var childTask = new[] 

                { 

                 tf.StartNew(()=>ConcreteTask(cts.Token)), 

                 tf.StartNew(()=>ConcreteTask(cts.Token)), 

                 tf.StartNew(()=>ConcreteTask(cts.Token)) 

                };

                Thread.Sleep(5000);//此處睡眠等任務開始一定時間後才取消任務 

                cts.Cancel(); 

            } 

            );

            parent.Start();//開始執行任務 

任務調度

任務的調度通過調度程序來實現的,目前,.NET 4.0內置兩種任務調度程序:線程池任務調度程序(thread pool task scheduler)和同步上下文任務調度程序(synchronization context task scheduler)。默認情況下,應用程序使用線程池任務調度程序調用線程池的工作線程來完成任務,如受計算限制的異步操作。同步上下文任務調度程序通常使用UI線程來完成與Windows Forms,Windows Presentation Foundation(WPF)以及SilverLight應用程序相關的任務。

   可喜的是,.NET 4.0 提供了TaskScheduler抽象類供開發人員繼承來實現自定義任務調度程序的開發,有興趣的同學可以試試。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章