• C#线程学习笔记三:线程池中的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.
    ", 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}
     CurrentThreadId is:{1}
     CurrentThread is background:{2}
     WorkerThreadNumber is:{3}
     IOThreadNumbers is:{4}
    ",
                    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线程去执行回调函数的,同时在项目的binDebug文件目录下生成了一个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}
     CurrentThreadId is:{1}
     CurrentThread is background:{2}
     WorkerThreadNumber is:{3}
     IOThreadNumbers is:{4}
    ",
                    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}
     CurrentThreadId is:{1}
     CurrentThread is background:{2}
     WorkerThreadNumber is:{3}
     IOThreadNumbers is:{4}
    ",
                    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);
                }
            }
        }

        运行结果如下:

  • 相关阅读:
    rails学习笔记(6)
    流程图好工具推荐JUDE
    流程图好工具推荐JUDE
    rails学习笔记(5)
    [转载 js]JsDoc Toolkit:Javascript文档利器
    ruby学习笔记(7)
    end_form_tag 已经在rails2.x中去掉了
    [转载 js]JsDoc Toolkit:Javascript文档利器
    rails学习笔记(5)
    ios 防止按钮快速点击造成多次响应的避免方法。
  • 原文地址:https://www.cnblogs.com/atomy/p/11984179.html
Copyright © 2020-2023  润新知