文章出處

接上文 多線程編程學習筆記——基礎(一)

 接上文 多線程編程學習筆記——基礎(二)

 接上文 多線程編程學習筆記——基礎(三)

 接上文 多線程編程學習筆記——線程同步(一)

 接上文 多線程編程學習筆記——線程同步(二)

  接上文 多線程編程學習筆記——線程同步(三)

接上文 多線程編程學習筆記——線程池(一)

接上文 多線程編程學習筆記——線程池(二)

 接上文 多線程編程學習筆記——線程池(三)

     

       前面我們學習了什么是線程,線程之間的同步,使用線程池。使用線程池可以減少我們大量短時間操作的并行線程所用的操作系統資源。

       在net framework 4.0中微軟又提供了一個新的異步操作的功能,叫做任務并行庫(TPL)。任務并行庫的核心是任務(task)。一個任務代表了一個異步操作,譔操作可以通過多種方式運行,可以使用或不使用獨立的線程。

        一個任務(Task)可以通過多種方式和其他任務組合起來使用。例如,可以同時開啟多個任務,等待所有任務完成,再起一個任務進行操作。一個任務可以有多個其他任務組成,這些任務也可以依次擁有自己的子任務。

         C#5.0及之后的版本都已經內置了對TPL的支持,允許我們使用await與async關鍵字進行任務執行。

         以下示例,我們使用.Net Framework 4.5之后版本。

 

一、   創建任務

        下面的示例,我們使用task構造函數創建了兩個任務。我們傳入了一個lambda表達式做為操作任務。然后使用start啟動任務。

        接著,我們使用task.Run和task.startNew方法來運行兩個任務。與使用task構造函數不同之處,在于這兩個被創建的任務會立即執行。所以無需顯式地調用 這些任務的Start方法。從task1到task4所有任務都是放在線程池中執行的,多次執行,可以發現執行順序是不一樣的。

          Task5,由于我們標記為了長時間運行,所以是一個單獨的線程,不是線程池中的線程來運行的。

  1. 代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; 

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

            Console.WriteLine("Task 運行示例 ————{0}",DateTime.Now);

           var task1 = new Task(() => TaskOper("Task1"));
            var task2 = new Task(() => TaskOper("Task2"));
            task1.Start();
            task2.Start();           

            Task.Factory.StartNew(() => TaskOper("Task 3"));
Task.Run(() => TaskOper("Task 4")); 

            //長時間運行
            Task.Factory.StartNew(() => TaskOper("Task 5"),TaskCreationOptions.LongRunning);
                      Thread.Sleep(1000);
            Console.ReadKey();
        }
        private static void TaskOper(string  name)
        {           

            Console.WriteLine("Task 運行在 線程 ID:{0} 上,這個線程是不是線程池中的線程:{1},名稱: {2}",            Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread, name); 

        }
    }
}

 

 

 2.運行結果如下圖。我把程序運行了兩次。請自行查看不同之處。

 

二、   使用任務執行基本的操作

         本示例是從任務中獲取結果值。我們通過不同的執行結果來顯示在線程池中執行與在主線程中執行的不同之處。

 1. 代碼如下:

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

namespace ThreadTPLDemo
{

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Task 基本操作 ————");
            TaskOper("----主線程Task運行");

           Task<string> task1 =CreateTask("Task1");
            task1.Start();
            string result = task1.Result;
            Console.WriteLine(" 運行結果——{0}", result); 

            Task<string> task2 = CreateTask("Task2");
            task2.RunSynchronously();
            result = task1.Result;
            Console.WriteLine(" 運行結果——{0}", result); 

            Task<string> task3 = CreateTask("Task3");
            task3.Start();
          while(!task3.IsCompleted)
            {
                Console.WriteLine(" 狀態——{0}", task3.Status);
                Thread.Sleep(500);
            }

            Console.WriteLine(" ——狀態—{0}", task3.Status);
            result = task3.Result;
            Console.WriteLine(" 運行結果——{0}", result);           

            Console.ReadKey();
        }
        private static string TaskOper(string  name)
        {         

            Console.WriteLine("Task 線程 ID:{0} 上,是不是線程池中的線程:{1},名稱: {2}",
            Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread, name);
            Thread.Sleep(2000);
            return string.Format("線程ID:{0},名稱:{1}", Thread.CurrentThread.ManagedThreadId,name);
        }
        static Task<string> CreateTask(string name)
        {
            return new Task<string>(() => TaskOper(name));

        }
    }
}

2.程序運行結果如下圖。

 

        首先直接運行TaskOper方法,根據程序運行結果,我們可以知道這個方法是被同步執行的。

        然后我們運行了task1,使用start方法啟動任務并等待結果。這個任務會被放在線程池中運行,而且主線程會等待,直到任務結束并返回結果。

        Task2與task1相似,Task2通過RunSynchronously()方法運行的。這個任務運行在主線程中,這個任務的輸出與TaskOper方法輸出結果一樣。這就是task的優勢,可以使用task對TaskOper方法進行優化,可以避免使用線程池來執行一些執行時間非常短的操作。

        Task3運行task1的方法,但是這次沒有阻塞主線程,只是在任務完成之前循環打印出任務狀態。


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()