欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#线程学习笔记三:线程池中的I/O线程

程序员文章站 2022-03-11 23:49:37
本笔记摘抄自: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();
        }
    }

    运行结果如下:

C#线程学习笔记三:线程池中的I/O线程

    从运行结果可以看出,此时是调用线程池中的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();
        }
    }

    运行结果如下:

C#线程学习笔记三:线程池中的I/O线程

    二、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);
            }
        }
    }

    运行结果如下:

C#线程学习笔记三:线程池中的I/O线程