一、Task的優點
  ThreadPool相比Thread來講具有了不少優點,可是ThreadPool卻又存在一些使用上的不方便。好比:
  ◆ ThreadPool不支持線程的取消、完成、失敗通知等交互性操做;
  ◆ ThreadPool不支持線程執行的前後次序;
  以往,若是開發者要實現上述功能,須要完成不少額外的工做,如今,FCL中提供了一個功能更強大的概念:Task。Task在線程池的基礎上進行了優化,並提供了更多的API。在FCL4.0中,若是咱們要編寫多線程程序,Task顯然已經優於傳統的方式。
  如下是一個簡單的任務示例:

複製代碼
using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            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.ReadKey();
        }
    }
}
複製代碼

 

二、Task的用法
  2.一、建立任務
  無返回值的方式
  方式1:
  var t1 = new Task(() => TaskMethod("Task 1"));
  t1.Start();
  Task.WaitAll(t1);//等待全部任務結束 
  注:
  任務的狀態:
  Start以前爲:Created
  Start以後爲:WaitingToRun 

  方式2:
  Task.Run(() => TaskMethod("Task 2"));

  方式3:
  Task.Factory.StartNew(() => TaskMethod("Task 3")); 直接異步的方法 
  或者
  var t3=Task.Factory.StartNew(() => TaskMethod("Task 3"));
  Task.WaitAll(t3);//等待全部任務結束
  注:
  任務的狀態:
  Start以前爲:Running
  Start以後爲:Running

複製代碼
using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var t1 = new Task(() => TaskMethod("Task 1"));
            var t2 = new Task(() => TaskMethod("Task 2"));
            t2.Start();
            t1.Start();
            Task.WaitAll(t1, t2);
            Task.Run(() => TaskMethod("Task 3"));
            Task.Factory.StartNew(() => TaskMethod("Task 4"));
            //標記爲長時間運行任務,則任務不會使用線程池,而在單獨的線程中運行。
            Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);

            #region 常規的使用方式
            Console.WriteLine("主線程執行業務處理.");
            //建立任務
            Task task = new Task(() =>
            {
                Console.WriteLine("使用System.Threading.Tasks.Task執行異步操做.");
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine(i);
                }
            });
            //啓動任務,並安排到當前任務隊列線程中執行任務(System.Threading.Tasks.TaskScheduler)
            task.Start();
            Console.WriteLine("主線程執行其餘處理");
            task.Wait();
            #endregion

            Thread.Sleep(TimeSpan.FromSeconds(1));
            Console.ReadLine();
        }

        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);
        }
    }
}
複製代碼

  async/await的實現方式:

複製代碼
using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        async static void AsyncFunction()
        {
            await Task.Delay(1);
            Console.WriteLine("使用System.Threading.Tasks.Task執行異步操做.");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(string.Format("AsyncFunction:i={0}", i));
            }
        }

        public static void Main()
        {
            Console.WriteLine("主線程執行業務處理.");
            AsyncFunction();
            Console.WriteLine("主線程執行其餘處理");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(string.Format("Main:i={0}", i));
            }
            Console.ReadLine();
        }
    }
}
複製代碼

  帶返回值的方式
  方式4:
  Task<int> task = CreateTask("Task 1");
  task.Start(); 
  int result = task.Result;

複製代碼
using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static Task<int> CreateTask(string name)
        {
            return new Task<int>(() => TaskMethod(name));
        }

        static void Main(string[] args)
        {
            TaskMethod("Main Thread Task");
            Task<int> task = CreateTask("Task 1");
            task.Start();
            int result = task.Result;
            Console.WriteLine("Task 1 Result is: {0}", result);

            task = CreateTask("Task 2");
            //該任務會運行在主線程中
            task.RunSynchronously();
            result = task.Result;
            Console.WriteLine("Task 2 Result is: {0}", result);

            task = CreateTask("Task 3");
            Console.WriteLine(task.Status);
            task.Start();

            while (!task.IsCompleted)
            {
                Console.WriteLine(task.Status);
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
            }

            Console.WriteLine(task.Status);
            result = task.Result;
            Console.WriteLine("Task 3 Result is: {0}", result);

            #region 常規使用方式
            //建立任務
            Task<int> getsumtask = new Task<int>(() => Getsum());
            //啓動任務,並安排到當前任務隊列線程中執行任務(System.Threading.Tasks.TaskScheduler)
            getsumtask.Start();
            Console.WriteLine("主線程執行其餘處理");
            //等待任務的完成執行過程。
            getsumtask.Wait();
            //得到任務的執行結果
            Console.WriteLine("任務執行結果:{0}", getsumtask.Result.ToString());
            #endregion
        }

        static int 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);
            Thread.Sleep(TimeSpan.FromSeconds(2));
            return 42;
        }

        static int Getsum()
        {
            int sum = 0;
            Console.WriteLine("使用Task執行異步操做.");
            for (int i = 0; i < 100; i++)
            {
                sum += i;
            }
            return sum;
        }
    }
}
複製代碼

    async/await的實現:

複製代碼
using System;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        public static void Main()
        {
            var ret1 = AsyncGetsum();
            Console.WriteLine("主線程執行其餘處理");
            for (int i = 1; i <= 3; i++)
                Console.WriteLine("Call Main()");
            int result = ret1.Result;                  //阻塞主線程
            Console.WriteLine("任務執行結果:{0}", result);
        }

        async static Task<int> AsyncGetsum()
        {
            await Task.Delay(1);
            int sum = 0;
            Console.WriteLine("使用Task執行異步操做.");
            for (int i = 0; i < 100; i++)
            {
                sum += i;
            }
            return sum;
        }
    }
}
複製代碼

  2.二、組合任務.ContinueWith
   簡單Demo:

  Program

   任務的串行:

  Program

  子任務:

  Program

  動態並行(TaskCreationOptions.AttachedToParent) 父任務等待全部子任務完成後 整個任務纔算完成

  Program

  2.三、取消任務 CancellationTokenSource

  Program

  2.四、處理任務中的異常
  單個任務:

  Program

  多個任務:

  Program

    async/await的方式:

  Program

  2.五、Task.FromResult的應用

  Program

  2.六、使用IProgress實現異步編程的進程通知
  IProgress<in T>只提供了一個方法void Report(T value),經過Report方法把一個T類型的值報告給IProgress,而後IProgress<in T>的實現類Progress<in T>的構造函數接收類型爲Action<T>的形參,經過這個委託讓進度顯示在UI界面中。

  Program

  2.七、Factory.FromAsync的應用 (簡APM模式(委託)轉換爲任務)(BeginXXX和EndXXX)
  帶回調方式的

  Program

  不帶回調方式的

  Program
 
 
 

c#源碼的執行過程

 

我想也許要寫些東西,記錄我作程序員的日子吧

================================================

要講到C#源碼的執行過程 首先要提下程序集,由於Clr並非和託管摸塊打交道的,而是和程序集(dll,exe)

一、從哪裏來

   程序集是由一個或者多個託管模塊以及 資源文件等共同組成的,C#編譯器(csc.exe)再把源碼編程成IL代碼和元數據的時候,會進一步連同資源文件合併成程序集,

實際上就是個PE32文件,裏面包含一個清單文件 和多個託管模塊和資源(如圖),另外程序集中還有一些自描述信息。

  

 

 

二、執行過程

  編譯器生成好程序集之後,若是是可執行的程序集,會在Main方法執行以前,window會預先讀取程序集的頭文件(pe32),若是是x86則開一個32位的進程,x64的就開一個64位的進程

而後在進程空間裏面加載MSCOREE.DLL的x86 或者x64版本或者arm版本,而後進程的主線程會調用MSCOREE.DLL的一個方法,初始化Clr,而Clr會加載程序集exe,再調用其入口方法Main。

3.Main方法內部執行

   在Main執行以前,Clr 會檢測出方法引用的全部類型,(Console),而後在內存中分配對應數據類型的空間,這個地址裏面包含着這個類型全部的方法聲名,每一項都對應着Clr裏面的一個未編檔函數(JITCompiler)

首次運行Main方法的試試JITCompiler會被調用,在這個方法裏面1,負責在方法的實現類型中(console)程序集元數據中查詢該方法的IL方法 2,動態分配內存塊 3,把IL編譯成本機Cpu的指令,存儲到動態分配的空間裏面

4,修改這個條目的地址,使它指向動態分配的地址 5.跳轉到內存塊中的本機代碼執行,這時候執行的就是IL代碼的cpu機器碼

5.在次執行Console.WriteLine的時候,就不會運行JITCompiler,直接運行機器碼