none
为什么FileStream写文件用的是IO线程,读的时候却是工作线程呢,按理解应该是IO线程来做啊? RRS feed

  • 问题

  • 今天写了一个测试程序的,FileStream写文件用的是IO线程,读的时候却是工作线程呢,按理解应该是IO线程来做啊?下面是我程序代码?

    异步写入文件:

    using System;
    using System.IO;
    using System.Text;
    using System.Threading;
    
    namespace AsyncFile
    {
        class Program
        {
            static void Main(string[] args)
            {
                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 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 size is: {0} byte\n", writebytes.Length);
                // 调用异步写入方法比信息写入到文件中
                filestream.BeginWrite(writebytes, 0, writebytes.Length, new AsyncCallback(EndWriteCallback), filestream);
                filestream.Flush();
                Console.Read();
    
            }
    
            // 当把数据写入文件完成后调用此方法来结束异步写操作
            private static void EndWriteCallback(IAsyncResult asyncResult)
            {
                Thread.Sleep(500);
                PrintMessage("Asynchronous Method start");
    
                FileStream filestream = asyncResult.AsyncState as FileStream;
    
                // 结束异步写入数据
                filestream.EndWrite(asyncResult);
                filestream.Close();
            }
    
            // 打印线程池信息
            private static void PrintMessage(String data)
            {
                int workthreadnumber;
                int iothreadnumber;
    
                // 获得线程池中可用的线程,把获得的可用工作者线程数量赋给workthreadnumber变量
                // 获得的可用I/O线程数量给iothreadnumber变量
                ThreadPool.GetAvailableThreads(out workthreadnumber, out 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());
            }
        }
    }

    上面代码运行结果为(从截图中可以看出使用的是IO线程):

    但是读取文件内容的时候,却是使用工作者线程运行回调函数的,下面是代码:

    using System;
    using System.IO;
    using System.Text;
    using System.Threading;
    
    namespace AsyncFileRead
    {
        class Program
        {
            const int maxsize = 1024;
            static byte[] readbytes = new byte[maxsize];
            static void Main(string[] args)
            {
                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();
            }
    
            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();
            }
    
            // 打印线程池信息
            private static void PrintMessage(String data)
            {
                int workthreadnumber;
                int iothreadnumber;
    
                // 获得线程池中可用的线程,把获得的可用工作者线程数量赋给workthreadnumber变量
                // 获得的可用I/O线程数量给iothreadnumber变量
                ThreadPool.GetAvailableThreads(out workthreadnumber, out 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());
            }
        }
    }

    下面是运行结果:

    从截图可以看出工作者线程少了一个,IO线程却没变,我觉得应该结果也是由IO线程运行回调方法的,则IO线程数量会减1,工作者线程不会变的,希望大家可以帮助我解决这个疑惑,谢谢大家


    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. my sample

    2013年4月26日 17:41

答案

  • 这是因为FileStream的文件容量小于缓冲值1024所致的。此时文件将会一次性读取或写入,而系统将启动工作者线程而非I/O线程来处理回调函数

    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. my sample

    2013年5月2日 15:28
  • 这个问题我自己找到答案了,这里分享出来。

    工作者线程是由CPU去执行工作的,然而IO线程是由设备驱动去只想工作的,此时CPU并不进行任何工作,IO线程也不做任何事情,只是用来通知你的代码IO操作是否完成。所以对于写文件之所以是IO线程,因为FileStream调用BeginWrite方法,此时需要线程池需要开启一个IO线程去监视硬盘驱动是否把内容写入到文件中了,此时没有CPU的任何事情,写文件的操作是由硬盘驱动去操作的,所以开启的是IO现场,然而读文件操作开启的工作者线程,主要是对于线程池来说,读文件这个操作的过程需要用到CPU操作,CPU需要把读取的内容从内存中读取出来,所以开启的是工作者线程,看到这里,可能你会觉得线程池应该开启IO线程和工作者两个线程的,之所以此时线程池没有另外运行IO线程,是因为之前写入文件时创建的IO线程本来只是告知IO操作完成的操作,其他事情也没做,所以线程池在这里就觉得没必要再创建IO线程了,完全可以由工作者线程去读取内存中的内容,如果IO操作完成就读取内容显示出来,如果没有完成,工作者线程就等待。
    这些完全是由线程池本身的机制决定的。还有FileStream类本身实现有关。
    希望我清楚地解释了这个问题。


    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. my sample

    2013年4月27日 17:24

全部回复

  • 这个问题我自己找到答案了,这里分享出来。

    工作者线程是由CPU去执行工作的,然而IO线程是由设备驱动去只想工作的,此时CPU并不进行任何工作,IO线程也不做任何事情,只是用来通知你的代码IO操作是否完成。所以对于写文件之所以是IO线程,因为FileStream调用BeginWrite方法,此时需要线程池需要开启一个IO线程去监视硬盘驱动是否把内容写入到文件中了,此时没有CPU的任何事情,写文件的操作是由硬盘驱动去操作的,所以开启的是IO现场,然而读文件操作开启的工作者线程,主要是对于线程池来说,读文件这个操作的过程需要用到CPU操作,CPU需要把读取的内容从内存中读取出来,所以开启的是工作者线程,看到这里,可能你会觉得线程池应该开启IO线程和工作者两个线程的,之所以此时线程池没有另外运行IO线程,是因为之前写入文件时创建的IO线程本来只是告知IO操作完成的操作,其他事情也没做,所以线程池在这里就觉得没必要再创建IO线程了,完全可以由工作者线程去读取内存中的内容,如果IO操作完成就读取内容显示出来,如果没有完成,工作者线程就等待。
    这些完全是由线程池本身的机制决定的。还有FileStream类本身实现有关。
    希望我清楚地解释了这个问题。


    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. my sample

    2013年4月27日 17:24
  • Hi Learning hard,

    感谢你的分享。


    Bob Shen
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2013年4月29日 7:30
    版主
  • 这是因为FileStream的文件容量小于缓冲值1024所致的。此时文件将会一次性读取或写入,而系统将启动工作者线程而非I/O线程来处理回调函数

    If my post is helpful,please help to vote as helpful, if my post solve your question, please help to make it as answer. my sample

    2013年5月2日 15:28