.NET基础拾遗(7)多线程开发基础3

一.如何使用异步模式?

  异步模式是在处理流类型时经常采用的一种方式,其应用的领域相当广阔,包括读写文件、网络传输、读写数据库,甚至可以采用异步模式来做任何计算工作。相对于手动编写线程代码,异步模式是一个高效的编程模式。

  (1)所谓异步模式是个什么鬼?

     在启动一个操作之后可以继续执行其他工作而不会发生阻塞

         以读取文件为例,在同步模式下,当程序执行到Read方法时,需要等到读取动作结束后才能继续往下执行。而异步模式则可以简单地通知开始读取任务之后,继续其他的操作。 异步模式的优点就在于不需要使当前线程等待,而可以充分地利用CPU时间。

异步模式区别于线程池机制在于允许程序查看操作的执行状态,而利用线程池的后台线程,则无法确切地知道操作的进行状态以及其是否已经结束。

  使用异步模式可以通过一些异步聚集技巧来查看异步操作的结果,所谓的聚集技巧是指查看操作是否结束的方法,方式是:在调用BeingXXX方法时传入操作结束后需要执行的方法(又称为回调方法),同时把执行异步操作的对象传入以便执行EndXXX方法

  (2)使用异步模式读取一个文件

  下面的示例代码中:

  ① 主线程中负责开始异步读取并传入聚集时需要使用的方法和状态对象:

    partial class Program
    {
        // 测试文件
        private const string testFile = @"C:AsyncReadTest.txt";
        private const int bufferSize = 1024;

        static void Main(string[] args)
        {
            // 删除已存在文件
            if (File.Exists(testFile))
            {
                File.Delete(testFile);
            }

            // 写入一些东西以便后面读取
            using (FileStream stream = File.Create(testFile))
            {
                string content = "我是文件具体内容,我是不是帅得掉渣?";
                byte[] contentByte = Encoding.UTF8.GetBytes(content);
                stream.Write(contentByte, 0, contentByte.Length);
            }

            // 开始异步读取文件具体内容
            using (FileStream stream = new FileStream(testFile, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, FileOptions.Asynchronous))
            {
                byte[] data = new byte[bufferSize];
                // 将自定义类型对象实例作为参数
                ReadFileClass rfc = new ReadFileClass(stream, data);
                // 开始异步读取
                IAsyncResult result = stream.BeginRead(data, 0, data.Length, FinshCallBack, rfc);
                // 模拟做了一些其他的操作
                Thread.Sleep(3 * 1000);
                Console.WriteLine("主线程执行完毕,按回车键退出程序");
            }

            Console.ReadKey();
        }
    }
View Code

  ② 定义了完成异步操作读取之后需要调用的方法,其逻辑是简单地打印出文件的内容:

    partial class Program
    {
        /// <summary>
        /// 完成异步操作后的回调方法
        /// </summary>
        /// <param name="result">状态对象</param>
        private static void FinshCallBack(IAsyncResult result)
        {
            ReadFileClass rfc = result.AsyncState as ReadFileClass;
            if (rfc != null)
            {
                // 必须的步骤:让异步读取占用的资源被释放掉
                int length = rfc.stream.EndRead(result);
                // 获取读取到的文件内容
                byte[] fileData = new byte[length];
                Array.Copy(rfc.data, 0, fileData, 0, fileData.Length);
                string content = Encoding.UTF8.GetString(fileData);
                // 打印读取到的文件基本信息
                Console.WriteLine("读取文件结束:文件长度为[{0}],文件内容为[{1}]", length.ToString(), content);
            }
        }
    }
View Code

  ③ 定义了作为状态对象传递的类型,这个类型对所有需要传递的数据包进行打包:

    /// <summary>
    /// 传递给异步操作的回调方法
    /// </summary>
    public class ReadFileClass
    {
        // 以便回调方法中释放异步读取的文件流
        public FileStream stream;
        // 文件内容
        public byte[] data;

        public ReadFileClass(FileStream stream,byte[] data)
        {
            this.stream = stream;
            this.data = data;
        }
    }
View Code

  下图展示了该实例的执行结果:

  如上面的实例,使用回调方法的异步模式需要将异步操作的对象及操作的结果数据都打包到一个类型里以便能够传递回给回调的委托方法,这样在委托方法中才能够有机会处理操作的结果且调用EndXXX方法以释放资源。

原文地址:https://www.cnblogs.com/tiantianle/p/5932262.html