C#線程學習筆記三:線程池中的I/O線程

来源:https://www.cnblogs.com/atomy/archive/2019/12/05/11984179.html
-Advertisement-
Play Games

本筆記摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/20/MultiThreads.html,記錄一下學習過程以備後續查用。 一、I/O線程實現對文件的非同步 1.1 I/O線程介紹: 對於線程所執行的任務來說,可以把線程分為兩種類型:工作者線程和 ...


    本筆記摘抄自: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);
            }
        }
    }

    運行結果如下:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 添加源 sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm 安裝Nginx sudo yum install -y nginx 直到出現 Co ...
  • 摘要:HALCON數據類型:Iconic Variables(圖形變數)、Control Variables(控制變數)。在C#中,圖形變數用HObject聲明,控制變數用HTuple聲明。(halcon數據類型被封裝成類)。 一,HALCON中變數導成C#變數 1,圖形變數 圖像變數 HObjec ...
  • 由於之前在網上查閱一些資料發現總是不能編譯通過,不能正常使用,現把能正常使用的代碼貼出: /// <summary> /// Excel導入幫助類 /// </summary> public class ImportExcelUtil<T> where T : new() { //合法文件擴展名 p ...
  • [toc] C (讀作 “See Sharp”)是一種簡單易用的新式編程語言,不僅面向對象,還類型安全。 C 源於 C 語言系列,可用 C 構建在多種操作系統(平臺)上運行的軟體組件和應用程式。 因為本系列文章會廣泛地使用 C 代碼示例,所以我們先來看看 C 程式的樣子,還有它的不同部分代表什麼意思 ...
  • 因為之前沒有接觸NPOI過這個插件,所以幾乎都是自己一邊百度摸索一邊學習。 這個插件對於Excel的數據導入和導出,可以說是很方便了, 但是對於導出word文檔,可以說是很少的,百度了很多....也不停止地去試代碼,於是整理出自己的一些看法,方便記錄代碼。 話不多說,上代碼... 用這個插件你需要準 ...
  • AMP(加速的移動頁面)是Google的開發人員軟體包,它允許開發負載更快的輕量級系統。AMP是由HTML,JavaScript和CSS組成的框架,它們是為用戶提供Web內容優先格式的標準。 Aspose.Email for .NET是一套全面的電子郵件處理API,可用於構建跨平臺應用程式。近期的更 ...
  • 1、先創建 .net core Web 應用程式,選擇API 2、安裝 Nuget 包:Nlog.Web.AspNetCore install-package Nlog install-package Nlog.Web.AspNetCore 或者打開Nuget管理界面搜索Nlog.Web.AspNe ...
  • 什麼是過濾器? 過濾器的類型與作用 定義過濾器 授權過濾器 動作過濾器 結果過濾器 異常處理過濾器 過濾器的使用方法 總結 什麼是過濾器? 通過上一篇關於Controller控制器的文章我們知道,MVC中的每一個請求,都會分配給相應的控制器(Controller)和對應的行為方法(Action)去處 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...