本筆記摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/20/MultiThreads.html,記錄一下學習程序以備后續查用,
一、I/O執行緒實作對檔案的異步
1.1 I/O執行緒介紹:
對于執行緒所執行的任務來說,可以把執行緒分為兩種型別:作業者執行緒和I/O執行緒,
作業者執行緒用來完成一些計算的任務,在任務執行的程序中,需要CPU不間斷地處理,所以,在作業者執行緒的執行程序中,CPU和執行緒的資源是充分利用的,
I/O執行緒主要用來完成輸入和輸出的作業,在這種情況下, 計算機需要I/O設備完成輸入和輸出的任務,在處理程序中,CPU是不需要參與處理程序的,此時正在運行的執行緒
將處于等待狀態,只有等任務完成后才會有事可做, 這樣就造成執行緒資源浪費的問題,為了解決這樣的問題,可以通過執行緒池來解決這樣的問題,讓執行緒池來管理執行緒,
對于I/O執行緒,我們可以將輸入輸出操作分成三個步驟:啟動、實際輸入輸出、處理結果,用于實際輸入輸出可由硬體完成,并不需要CPU的參與,而啟動和處理結果也可以
不在同一個執行緒上,這樣就可以充分利用執行緒資源,在.Net中通過以Begin開頭的方法來完成啟動,以End開頭的方法來處理結果,這兩個方法可以運行在不同的執行緒,這樣我們
就實作了異步編程了,
1.2 .Net中如何使用異步
注意:
其實當我們呼叫Begin開頭的方法,就是將一個I/O執行緒排入到執行緒池中(由.Net機制幫我們實作),
注:作業者執行緒由執行緒池管理,直接呼叫ThreadPool.QueueUserWorkItem方法來將作業者執行緒排入到執行緒池中,
在.NET Framework中的FCL中有許多型別能夠對異步操作提供支持,其中在FileStream類中就提供了對檔案的異步操作的方法,
FileStream類要呼叫I/O執行緒要實作異步操作,首先要建立一個FileStream物件,然后通過下面的建構式來初始化FileStream物件實作異步操作(異步讀取和異步寫入):
public FileStream (string path, FileMode mode, FileAccess access, FileShare share,int bufferSize,bool useAsync)
其中path代表檔案的相對路徑或絕對路徑,mode代表如何打開或創建檔案,access代表訪問檔案的方式,share代表檔案如何由行程共享,buffersize代表緩沖區的大小,
useAsync代表使用異步I/O還是同步I/O,設定為true時,表示使用異步I/O,
下面代碼演示異步寫入檔案:
class Program { static void Main(string[] args) { #region I/O執行緒:異步寫入檔案 const int maxSize = 100000; ThreadPool.SetMaxThreads(1000, 1000); PrintMessage("Main thread start."); //初始化FileStream物件 FileStream fileStream = new FileStream("Test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 100, true); //列印檔案流打開的方式 Console.WriteLine("Filestream is {0}opened with asynchronously.", fileStream.IsAsync ? "" : "not "); byte[] writeBytes = new byte[maxSize]; string writeMessage = "An operation use asynchronous method to write message......"; writeBytes = Encoding.Unicode.GetBytes(writeMessage); Console.WriteLine("Message sizes is:{0} bytes.\n", writeBytes.Length); //呼叫異步寫入方法將資訊寫入到檔案中 fileStream.BeginWrite(writeBytes, 0, writeBytes.Length, new AsyncCallback(EndWriteCallback), fileStream); fileStream.Flush(); Console.Read(); #endregion } /// <summary> /// 列印執行緒池資訊 /// </summary> /// <param name="data"></param> private static void PrintMessage(string data) { //獲得執行緒池中可用的作業者執行緒數量及I/O執行緒數量 ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n", data, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground.ToString(), workThreadNumber.ToString(), ioThreadNumber.ToString()); } /// <summary> /// 當資料寫入檔案完成后呼叫此方法來結束異步寫操作 /// </summary> /// <param name="asyncResult"></param> private static void EndWriteCallback(IAsyncResult asyncResult) { Thread.Sleep(500); PrintMessage("Asynchronous method start."); FileStream filestream = asyncResult.AsyncState as FileStream; //結束異步寫入資料 filestream.EndWrite(asyncResult); filestream.Close(); } }
運行結果如下:

從運行結果可以看出,此時是呼叫執行緒池中的I/O執行緒去執行回呼函式的,同時在專案的bin\Debug檔案目錄下生成了一個Test.txt檔案,
下面代碼演示異步讀取檔案:
class Program { //異步讀取檔案 const int maxSize = 1024; private static readonly byte[] readBytes = new byte[maxSize]; static void Main(string[] args) { #region I/O執行緒:異步讀取檔案 ThreadPool.SetMaxThreads(1000, 1000); PrintMessage("Main thread start."); // 初始化FileStream物件 FileStream fileStream = new FileStream("Test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 100, false); // 異步讀取檔案內容 fileStream.BeginRead(readBytes, 0, readBytes.Length, new AsyncCallback(EndReadCallback), fileStream); Console.Read(); #endregion } /// <summary> /// 列印執行緒池資訊 /// </summary> /// <param name="data"></param> private static void PrintMessage(string data) { //獲得執行緒池中可用的作業者執行緒數量及I/O執行緒數量 ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n", data, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground.ToString(), workThreadNumber.ToString(), ioThreadNumber.ToString()); } /// <summary> /// 當資料讀取檔案完成后呼叫此方法來結束異步寫操作 /// </summary> /// <param name="asyncResult"></param> private static void EndReadCallback(IAsyncResult asyncResult) { Thread.Sleep(1000); PrintMessage("Asynchronous method start."); // 把AsyncResult.AsyncState轉換為State物件 FileStream readStream = (FileStream)asyncResult.AsyncState; int readLength = readStream.EndRead(asyncResult); if (readLength <= 0) { Console.WriteLine("Read error."); return; } string readMessage = Encoding.Unicode.GetString(readBytes, 0, readLength); Console.WriteLine("Read message is :" + readMessage); readStream.Close(); } }
運行結果如下:

二、I/O執行緒實作對請求的異步
我們同樣可以利用I/O執行緒來模擬瀏覽器對服務器請求的異步操作,在.NET類別庫中的WebRequest類提供了異步請求的支持,
下面代碼演示異步請求:
class Program { static void Main(string[] args) { #region I/O執行緒:異步請求 ThreadPool.SetMaxThreads(1000, 1000); PrintMessage("Main thread start."); // 發出一個異步Web請求 WebRequest webrequest = WebRequest.Create("https://www.cnblogs.com/"); webrequest.BeginGetResponse(ProcessWebResponse, webrequest); Console.Read(); #endregion } /// <summary> /// 列印執行緒池資訊 /// </summary> /// <param name="data"></param> private static void PrintMessage(string data) { //獲得執行緒池中可用的作業者執行緒數量及I/O執行緒數量 ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n", data, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground.ToString(), workThreadNumber.ToString(), ioThreadNumber.ToString()); } /// <summary> /// Web請求回呼函式 /// </summary> /// <param name="result"></param> private static void ProcessWebResponse(IAsyncResult result) { Thread.Sleep(500); PrintMessage("Asynchronous method start."); WebRequest webRequest = (WebRequest)result.AsyncState; using (WebResponse wr = webRequest.EndGetResponse(result)) { Console.WriteLine("Content length is : " + wr.ContentLength); } } }
運行結果如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/96177.html
標籤:C#
