首頁 > 軟體

.Net中Task Parallel Library的基本用法

2022-10-04 14:00:09

我們知道,每個應用程式就是一個程序,一個程序有多個執行緒。Task Parallel Library為我們的非同步程式設計、多執行緒程式設計提供了強有力的支援,它允許一個主執行緒執行的同時,另外的一些執行緒或Task也同時執行。本篇體驗基本用法。

基本用法

Taks的建構函式接收的型別是Action,也就是一個委託。

        static void Main(string[] args)
        {
            var t1 = new Task(() =>
            {
                Console.WriteLine("任務1開始");
                Thread.Sleep(1000);
                Console.WriteLine("任務1結束");
            });
            t1.Start();
            Console.ReadKey();
        }

如果把方法放到外面。

        static void Main(string[] args)
        {
            var t1 = new Task(() => DoSth(1,2000));
            t1.Start();
            Console.ReadKey();
        }
        static void DoSth(int id, int sleepTime)
        {
            Console.WriteLine("任務{0}開始",id);
            Thread.Sleep(sleepTime);
            Console.WriteLine("任務{0}結束",id);
        }

如果有多個Task同時執行。

        static void Main(string[] args)
        {
            var t1 = new Task(() => DoSth(1,2000));
            t1.Start();
            var t2 = new Task(() => DoSth(2, 1500));
            t2.Start();
            var t3 = new Task(() => DoSth(3, 3000));
            t3.Start();
            Console.ReadKey();
        }

如果有很多Task,每個Task手動啟動的話很費事,Task Parallel Library為我們準備了Task工廠。

        static void Main(string[] args)
        {
            var t1 = Task.Factory.StartNew(() => DoSth(1, 2000));
            var t2 = Task.Factory.StartNew(() => DoSth(2, 1500));
            var t3 = Task.Factory.StartNew(() => DoSth(3, 3000));
            Console.ReadKey();
        }

如果我們想在一個任務結束之後立即執行某個任務,可以使用ContinueWith方法。

        static void Main(string[] args)
        {
            var t1 = Task.Factory.StartNew(() => DoSth(1, 2000)).ContinueWith((pre)=> DoOtherThing(4,2000)); 
            var t2 = Task.Factory.StartNew(() => DoSth(2, 1500));
            var t3 = Task.Factory.StartNew(() => DoSth(3, 3000));
            Console.ReadKey();
        }
        static void DoSth(int id, int sleepTime)
        {
            Console.WriteLine("任務{0}開始",id);
            Thread.Sleep(sleepTime);
            Console.WriteLine("任務{0}結束",id);
        }
        static void DoOtherThing(int id, int sleepTime)
        {
            Console.WriteLine("其他任務{0}開始", id);
            Thread.Sleep(sleepTime);
            Console.WriteLine("其他任務{0}結束", id);
        }

如果希望等待所有的Task執行完畢,使用WaitAll方法。

        static void Main(string[] args)
        {
            var t1 = Task.Factory.StartNew(() => DoSth(1, 2000));
            var t2 = Task.Factory.StartNew(() => DoSth(2, 1500));
            var t3 = Task.Factory.StartNew(() => DoSth(3, 3000));
            var taskList = new List<Task> {t1, t2, t3};
            Task.WaitAll(taskList.ToArray());
            Console.WriteLine("我是在所有Task執行完畢後才執行的");
            Console.ReadKey();
        }

如果想手動取消結束某個Task,需要為方法帶上CancellationToken型別引數。

        static void Main(string[] args)
        {
            var source = new CancellationTokenSource();
            try
            {
                var t1 =
                    Task.Factory.StartNew(() => DoSth(1, 1000, source.Token))
                        .ContinueWith((pre) => DoOtherThing(2, 2000));
                source.Cancel();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.GetType());
            }
            Console.WriteLine("haha");
            Console.ReadKey();
        }
        static void DoSth(int id, int sleepTime, CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("任務被取消");
                token.ThrowIfCancellationRequested();
            }
            
            Console.WriteLine("任務{0}開始",id);
            Thread.Sleep(sleepTime);
            Console.WriteLine("任務{0}結束",id);
        }
        static void DoOtherThing(int id, int sleepTime)
        {
            Console.WriteLine("其他任務{0}開始", id);
            Thread.Sleep(sleepTime);
            Console.WriteLine("其他任務{0}結束", id);
        }

如何從Task從獲取方法的返回結果呢?

        static void Main(string[] args)
        {
            Console.WriteLine("開始計算");
            Task<int> t = Task.Factory.StartNew(() => Sum(1, 2));
            Console.WriteLine("等待結果");
            Console.WriteLine(t.Result);
            Console.ReadKey();
        }
        static int Sum(int a, int b)
        {
            return a + b;
        }

後面一個Task獲取前面一個Task的返回值。

        static void Main(string[] args)
        {
            Task<string> firstTask = Task.Factory.StartNew<string>(() =>
            {
                Console.WriteLine("第一個任務開始");
                return "hi from the one";
            });
            Task secondTask = firstTask.ContinueWith((prevoursTask) =>
            {
                Console.WriteLine("這裡是第二個任務,獲取到第一個任務的返回值是{0}",prevoursTask.Result,TaskContinuationOptions.OnlyOnRanToCompletion);
            });
            secondTask.Wait();
            Console.ReadKey();
        }

等待所有Task完成。

        static void Main(string[] args)
        {
           var t1 =  Task.Factory.StartNew(() =>
            {
                Console.WriteLine("第一個任務");
                Thread.Sleep(1000);
            });
            var t2 = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("第二個任務");
                Thread.Sleep(1000);
            });
            var taskList = new List<Task> {t1, t2};
            Task.Factory.ContinueWhenAll(taskList.ToArray(), (t) => { Console.WriteLine("所有任務完成我就出來"); });
            Console.ReadKey();
        }

如果是巢狀Task。

        static void Main(string[] args)
        {
            Task.Factory.StartNew(() =>
            {
                Task child = Task.Factory.StartNew(() =>
                {
                    Console.WriteLine("我是子任務");
                }, TaskCreationOptions.AttachedToParent);
            }).Wait();
            Console.ReadKey();
        }

啟動Task的幾種方式

1、通過Task.Factory.StartNew方法。

        static void Main(string[] args)
        {
            Task.Factory.StartNew(() => SaySth("hello"));
            Console.ReadKey();
        }
        static void SaySth(string msg)
        {
            Console.WriteLine(msg);
        }

2、通過Task的Start實體方法

        static void Main(string[] args)
        {
            var t = new Task(() => SaySth("hello"));
            t.Start();
            Console.ReadKey();
        }

或者乾脆用委託。

        static void Main(string[] args)
        {
            Task t = new Task(delegate {SaySth("hello");});
            t.Start();
            Console.ReadKey();
        }

3、Task的靜態方法Run

        static void Main(string[] args)
        {
            Task t = Task.Run(() => SaySth("hello"));
            Console.ReadKey();
        }
        static void SaySth(string msg)
        {
            Console.WriteLine(msg);
        }  

一個例子

比如說要下載某個頁面,在保持當前UI介面無影響的情況下,使用Task在後臺啟動任務下載某個頁面。

        static void Main(string[] args)
        {
            Console.WriteLine("介面內容");
            Task<string> r = DownloadAsync("http://www.baidu.com");
            while (!r.IsCompleted)
            {
                Console.Write(".");
                Thread.Sleep(250);
            }
            Console.WriteLine(r.Result);
            Console.ReadKey();
        }
        private static string DownloadWebPage(string url)
        {
            WebRequest request = WebRequest.Create(url);
            WebResponse response = request.GetResponse();
            var reader = new StreamReader(response.GetResponseStream());
            return reader.ReadToEnd();
        }
        private static Task<string> DownloadAsync(string url)
        {
            return Task.Factory.StartNew(() => DownloadWebPage(url));
        }

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對it145.com的支援。如果你想了解更多相關內容請檢視下面相關連結


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