接着上期的文章繼續說異步與並行程序員
並行來自於線程的方法實現,異步不必定。這句話,暈倒一大片程序員。編程
首先,多線程序是實現異步一種方法,二者的共同目的:使主線程保持對用戶操做的實時響應,如點擊、拖拽、輸入字符等。使主程序看起來實時都保持着等待用戶響應的狀態,然後臺卻有若干件事情在本身幹。按消耗資源所在地可分爲兩類:硬件異步類和CPU異步類。多線程
硬件異步的特色:將須要在後臺執行的操做甩給底層硬件去執行,不佔用線程和CPU資源。因此說,並非全部的異步都佔有線程的。異步
硬件異步類大概有如下這幾類。socket
應用程序範圍函數 |
支持包含異步方法的 API測試 |
Web 訪問google |
|
處理文件spa |
|
使用圖像處理 |
|
WCF 編程 |
|
與套接字處理 |
CPU經常使用的異步方式、方法
一、獨立的線程—ThreadStart
通常狀況下,要爲不會阻止其餘線程的相對較短的任務處理多個線程而且不須要對這些任務執行任何特定調度時,使用 ThreadPool 類是一種最簡單的方式。 可是,有多個理由建立您本身的線程:
若是您須要使一個任務具備特定的優先級。
若是您具備可能會長時間運行(並所以阻止其餘任務)的任務。
若是您須要將線程放置到單線程單元中(全部 ThreadPool 線程均處於多線程單元中)。
若是您須要與該線程關聯的穩定標識。 例如,您應使用一個專用線程來停止該線程,將其掛起或按名稱發現它。
若是您須要運行與用戶界面交互的後臺線程,.NET Framework 2.0 版提供了 BackgroundWorker 組件,該組件可使用事件與用戶界面線程的跨線程封送進行通訊。
二、ThreadPool—ThreadPool.QueueUserWorkItem(M())
三、任務,Task系列--普通任務、關聯的任務(Task<T>.ContinueWith(…))、父子任務、任務工廠(TaskTactory<TResult>)
四、Parallel靜態類--- System.Threading.Tasks.Parallel.For(…) System.Threading.Tasks.Parallel.ForEach(…) Parallel.Invoke(() => Sort());
五、PLINQ
六、定時器
到此只是簡單的基礎知識闡述。若是不太清楚,下面的陸續的文章將會一一講起。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Thread類(線程類)
除了使用委託建立線程以外,還可使用thread 類建立線程
static void Main(string[] args) { Thread t = new Thread(ThreadMain); t.Start(); Console.WriteLine("This ia a mian thread."); } static void ThreadMain() { Console.WriteLine("Running in a thread."); }
簡化以上代碼
static void Main(string[] args) { new Thread(() => Console.WriteLine("Running in a thread.") ).Start(); Console.WriteLine("This ia a mian thread."); }
再次見證 拉姆達(lambda)表達式與匿名方法 的威力。
在上面簡單的Thread類就建立並開始了一個線程。Thread類默認的是 IsBackground =false,也就是說它是前臺線程。
說到前臺線程與後臺線程,上一文章提到,當前臺進程中止的時候,後臺進程也將中止,當時是放在mian主線程測試的,必須關閉或結束主線程,看的不是太清楚
如今有了Thread類,下面的例子將會開啓不依懶主線程的測試。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { DateTime now = DateTime.Now; Thread t1 = new Thread(() => { Console.WriteLine("Running in a thread t1."); Func<decimal, int, decimal> f = (money, ms) => { Console.WriteLine("SaveBankAccountPersonA thread started! current run at threadID:" + Thread.CurrentThread.ManagedThreadId); Console.WriteLine("SaveBankAccountPersonA thread IsBackground " + Thread.CurrentThread.IsBackground); Thread.Sleep(ms); Console.WriteLine("SaveBankAccountPersonA thread completed!"); return ++money; }; var ar = f.BeginInvoke(1, 200, (r) => { if (r == null) { throw new ArgumentNullException("r"); } Thread.Sleep(1000); Console.WriteLine("AsycyCallBackCurrentMoneyPersonA:{0}", f.EndInvoke(r)); Console.WriteLine("AsycyCallBackRunTimePersonA:{0}", (DateTime.Now - now).TotalSeconds); Console.WriteLine("AsycyCallBackSaveBankAccountPersonA thread IsBackground " + Thread.CurrentThread.IsBackground); }, null); while (!ar.IsCompleted) { Console.WriteLine("threadT1 wating current run at treadID:" + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(50); } }); Thread t2 = new Thread(() => { Console.WriteLine("Running in a thread t2."); Func<decimal, int, decimal> f = (money, ms) => { Console.WriteLine("SaveBankAccountPersonB thread started! current run at threadID:" + Thread.CurrentThread.ManagedThreadId); Console.WriteLine("SaveBankAccountPersonB thread IsBackground " + Thread.CurrentThread.IsBackground); Thread.Sleep(ms); Console.WriteLine("SaveBankAccountPersonB thread completed!"); return ++money; }; var ar = f.BeginInvoke(1, 200, (r) => { if (r == null) { throw new ArgumentNullException("r"); } Console.WriteLine("AsycyCallBackCurrentMoneyPersonB:{0}", f.EndInvoke(r)); Console.WriteLine("AsycyCallBackRunTimePersonB:{0}", (DateTime.Now - now).TotalSeconds); Console.WriteLine("AsycyCallBackSaveBankAccountPersonB thread IsBackground " + Thread.CurrentThread.IsBackground); }, null); while (!ar.IsCompleted) { Console.WriteLine("threadT2 wating current run at treadID:" + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(50); } }); t1.Start(); t2.Start(); t1.Abort(); Console.WriteLine("This ia a mian thread."); Console.ReadKey(); } } }
上面的代碼不少,對上一文章的進行擴展。分別啓用兩個線程t1和t2 ,並在每一個線程里加入異步委託A和B,從而開始新的後臺線程(異步委託默認是後臺線程)
上面這張圖,t1尚未來及運行,就已中止,下面這張圖,t1運行起來了
可是A仍是沒有運行起來,充分說明A一併被t1中止
後臺線程A和B 同時擁有兩個回調函數 ,在A回調函數裏 加入了Sleep(1000) 延遲1秒,緊接着外面t1.Abort();結束前臺線程t1。從而達到,外面的t1前臺線程結束時後臺線程A尚未來及結束(實際上已強制性並隨t1前臺線程結束了!)
這樣就驗證了,前臺線程結束所依懶的後臺線程所並隨結束的事實!代碼就是最好的說明
小結:本節在文章一節中着重闡述的前臺線程與後臺線程做了在Thread類基礎上作了實例論證,從而證實,後臺線程的生命週期由依懶的前臺線程結束而結束。
同時也將異步與多線程進一步舉例說明,線程只是異步的一種實現方法!
未完待續...