在前面3篇文章,我已经介绍了异步的工作原理和相关方法和参数的应用.下面我们介绍Stream流的操作, 并使用System.IO.FileStream来揭开如何开发异步的Stream(System.IO.Stream)读/写操作

异步的Stream/写操作

下面是继承于System.IO.Stream的类
 System.IO.Stream
    Microsoft.JScript.COMCharStream
    System.IO.BufferedStream
    System.IO.FileStream
    System.IO.MemoryStream
    System.IO.UnmanagedMemoryStream
    System.Security.Cryptography.CryptoStream
    System.Printing.PrintQueueStream
    System.IO.Pipes.PipeStream
    System.Data.OracleClient.OracleBFile
    System.Data.OracleClient.OracleLob
    System.IO.Compression.DeflateStream
    System.IO.Compression.GZipStream
    System.Net.Sockets.NetworkStream
    System.Net.Security.AuthenticatedStream

在System.IO.Stream中提供了异步的读/写(Read/Write)行为,上面继承于System.IO.Stream的类都具有同样的异步操作行为.在.Net Framework框架中,微软设计师使用Begin+同步方法名/ End+同步方法名来设计异步方法的规则,基本上我们在微软MSDN看到的 BeginXXX + EndXXX都是异步的方法,并且当我们在某个类中看到BeginInvoke / EndInvoke,都是微软提供的最原始的异步方法.在System.IO.Stream类中表现为BeginRead+EndRead / BeginWrite/EndWrite.

我们来看一个例子,FileStream(System.IO),Read / BeginRead+EndRead,读取文件内容,开始我们使用同步方法.

同步调用

Code1.1

1static class Program
 2    {
 3        static string path = @"c:\file.txt";//确保你本地有这个文件
 4        const int bufferSize = 5;//演示,一次只读取5 byte
 5        static void Main()
 6        {
 7            FileStream fs = new FileStream(path, FileMode.Open,
 8FileAccess.Read, FileShare.Read, 20480, false);//同步调用false
 9            using (fs)//使用using来释放FileStream资源
10            {
11                byte[] data = new byte[bufferSize];
12                StringBuilder sb = new StringBuilder(500);
13                int byteReads;
14                do// 不断循环,直到读取完毕
15                {
16                    byteReads = fs.Read(data, 0, data.Length);
17                    sb.Append(Encoding.ASCII.GetString(data, 0, byteReads));
18                } while (byteReads > 0);
19                Console.WriteLine(sb.ToString());//输出到工作台
20
21            }//自动清除对象资源,隐式调用fs.Close();
22            Console.ReadLine();// 让黑屏等待,不会直接关闭..
23        }
24    }

方法非常简单,它会构造一个 FileStream 对象,调用 Read方法,不断循环读取数据。C# using 语句可确保完成数据处理后会关闭该 FileStream 对象。

下面我们看异步调用(BeginRead/EndRead)

异步调用

Code1.2

1static class Program
 2    {
 3        static string path = @"c:\file.txt";//确保你本地有这个文件
 4        const int bufferSize = 5;//演示,一次只读取5 byte
 5        static byte[] data;
 6        static void Main()
 7        {
 8            data = new byte[bufferSize];
 9            FileStream fs = new FileStream(path, FileMode.Open,
10FileAccess.Read, FileShare.Read, 20480, true);//设置异步调用true, 注意0
11
12            //异步读取文件,把FileStream对象作为异步的参数// <-
13            AsyncCallback callback = new AsyncCallback(OnReadCompletion);
14            IAsyncResult async = fs.BeginRead(data, 0, bufferSize, callback, fs); // <-
15
16            Console.ReadLine();// 让黑屏等待,不会直接关闭..
17        }
18        static void OnReadCompletion(IAsyncResult asyncResult)
19        {
20            FileStream fs = asyncResult.AsyncState as FileStream;
21            int bytesRead = fs.EndRead(asyncResult);
22            //输出到工作台
23            Console.Write(Encoding.ASCII.GetString(data, 0, bytesRead));
24            //不断循环,直到读取完毕
25            if (bytesRead > 0)
26                fs.BeginRead(data, 0, bufferSize, OnReadCompletion, fs);
27            else
28                fs.Close(); //当全部读取完毕,显式释放资源
29        }
30    }

方法是使用BeginRead和EndRead 完成的, 我们注意到方法不能使用 C# using 语句(释放资源),因为 FileStream 是在一个主线程中打开,然后在另一个线程中关闭的,而是通过把FileStream 作为参数的形式来在另外一个线程中关闭的(fs.Close();),查看红色部分.

注意0:创建FileStram 对象,如果没有FileStream fs = new FileStream(path, FileMode.Open,FileAccess.Read, FileShare.Read, 20480, true); bool useAsync=true 或者构造FileStream(String, FileMode, FileAccess, FileShare, Int32, FileOptions) FileOptions = FileOptions.Asynchronous 时,  即使使用了BeginRead/EndRead, 程序也是在同步执行方法,FileStream 对象会使用其他线程来模仿异步行为,反而降低了应用程序的性能.

下面我将通过使用C# 匿名方法(C# 2.0) 和 lambda 表达式(C# 3.0引入的一个新功能) 来完成上面操作,如果对这个不熟悉的朋友可以查看下面文章.

匿名方法:http://www.microsoft.com/china/msdn/library/langtool/vcsharp/CreElegCodAnymMeth.mspx?mfr=true

lambda 表达式:http://msdn.microsoft.com/zh-cn/magazine/cc163362.aspx

C# 匿名方法  lambda 表达式

1,匿名方法:
Code1.3

1static class Program
 2    {
 3        static string path = @"c:\file.txt";//确保你本地有这个文件
 4        const int bufferSize = 5;//演示,一次只读取5 byte
 5        static void Main()
 6        {
 7            byte[] data = new byte[bufferSize];
 8            //[1]
 9            FileStream fs = new FileStream(path, FileMode.Open,
10FileAccess.Read, FileShare.Read, 20480, true);//设置异步调用true
11            //使用匿名委托方式
12            AsyncCallback callback = null; //注意1
13            callback = delegate(IAsyncResult asyncResult)//匿名方法
14            {
15                int bytesRead = fs.EndRead(asyncResult);//[2]
16                Console.Write(Encoding.ASCII.GetString(data, 0, bytesRead));//输出到工作台
17                //不断循环,直到读取完毕
18                if (bytesRead > 0)
19                    fs.BeginRead(data, 0, bufferSize, callback, null);//[3]
20                else
21                    fs.Close();//[4]
22            };
23
24            //异步读取文件
25            IAsyncResult async = fs.BeginRead(data, 0, bufferSize, callback, null);
26
27            Console.ReadLine();// 让黑屏等待,不会直接关闭..
28        }
29    }

对比Code1.2代码我们可以看出, 匿名方法非常出色的完成我们功能, 在匿名方面体内 fs ([2][3][4])像普通变量一样执行引用FileStream([1]) 对象,而不需要任何的类型转换. 对象在方法之间轻松实现传递,并且从一个线程轻松迁移到另一个线程, 对APM 编程而言这是十分完美的,但实际上编译器会重新编写您的代码,从堆栈中取出这些变量,并将它们作为字段嵌入对象。由于编译器会自动执行所有的工作,您可以很轻松地将最后一个参数的空值传递到 BeginRead 方法,因为现在没有必要再在方法和线程之间显式传递的数据了。

注意1: 必须先AsyncCallback callback = null; 要不编程器会告诉你错误:” Use of unassigned local variable 'callback '”.

2,Lambda 表达式

我们只需要简单的修改(在执行同一操作,lambda 表达式语法比 C# 匿名方法更简洁),匿名方法,把Code1.3中红色部分的
callback = delegate(IAsyncResult asyncResult)
修改成
callback = asyncResult =>

下面是完整代码.

Code1.4


static class Program
    {
        static string path = @"c:\file.txt";//确保你本地有这个文件
        const int bufferSize = 5;//演示,一次只读取5 byte
        static void Main()
        {
            byte[] data = new byte[bufferSize];

FileStream fs = new FileStream(path, FileMode.Open,
FileAccess.Read, FileShare.Read, 20480, true);//设置异步调用true
            //使用lambda 表达式
            AsyncCallback callback = null;//注意1
            callback = asyncResult =>
            {
                int bytesRead = fs.EndRead(asyncResult);
                Console.Write(Encoding.ASCII.GetString(data, 0, bytesRead));//输出到工作台
                //不断循环,直到读取完毕
                if (bytesRead > 0)
                    fs.BeginRead(data, 0, bufferSize, callback, null);
                else
                    fs.Close();
            };

//异步读取文件
            IAsyncResult async = fs.BeginRead(data, 0, bufferSize, callback, null);

Console.ReadLine();// 让黑屏等待,不会直接关闭..
        }
    }

最后,我们来看看异步的写操作(BeginWrite/EndWrite)

Code2

1static class Program
 2    {
 3        static void Main()
 4        {
 5            FileStream fs = new FileStream("text.txt", FileMode.Create,
 6FileAccess.ReadWrite, FileShare.None, 20480, true);//设置异步调用true
 7            //输入信息
 8            Console.Write("Please Enter:");
 9            byte[] data = Encoding.ASCII.GetBytes(Console.ReadLine());
10
11            //异步写文件
12            IAsyncResult async = fs.BeginWrite(data, 0, data.Length, asyncResult =>
13            {
14                fs.EndWrite(asyncResult);//写文件介绍,输出到text.txt文件中.
15                fs.Close();
16
17            }, null);
18
19            Console.ReadLine();// 让黑屏等待,不会直接关闭..
20        }
21    }

大家觉得是否很简单呢? 基本上所有具有异步行为的流(继承于System.IO.Stream)操作都可以按照类似于上面的代码编写. 当然其他异步行为也可以使用上面代码中的技巧. 在System.IO.Stream 中,提供了ReadTimeout/WriteTimeout 的超时处理,但是基类中是不支持的.会报 InvalidOperationException 异常,反编译可以看到throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TimeoutsNotSupported")).

下篇文章我会提供其他的例子来说明异步中的线程间通信.采用Window Forms程序.

以上有word 文档直接粘贴,排版可能不太好看,你可以通过下面来下载相应的代码/文档

1,文档

2,代码(VS2008开发,.Net Framework 3.5(C Sharp)编写)

转载于:https://www.cnblogs.com/ywsoftware/archive/2013/05/29/3105405.html

什么是.Net的异步机制(异步Stream读/写) - step 4相关推荐

  1. 实验九:采用异步方式实现文件读/写

    一:实验目的 (1)了解Windows系统异步文件读/写的概念. (2)熟悉Windows系统文件读/写相关的API. (3)掌握采用异步方式实现文件读/写的相关参数设置. 二:实验准备知识:文件异步 ...

  2. 实验九 使用异步方式实现文件读\写

    实验九 使用异步方式实现文件读\写 一.实验目的 了解Windows系统异步文件读/写的概念. 熟悉Windows系统文件读/写相关的API. 掌握采用异步方式实现文件读/写的相关参数设置. 二.实验 ...

  3. 跟着 Event loop 规范理解浏览器中的异步机制

    原文发自我的 GitHub blog,欢迎关注 前言 我们都知道 JavaScript 是一门单线程语言,这意味着同一事件只能执行一个任务,结束了才能去执行下一个.如果前面的任务没有执行完,后面的任务 ...

  4. 前端知识点回顾之重点篇——JavaScript异步机制

    JavaScript异步机制 来源:https://www.cnblogs.com/zhaodongyu/p/3922961.html JavaScript是单线程异步执行的,单线程意味着代码在任务队 ...

  5. 后台系统可扩展性学习笔记(十四)异步机制与MQ

    对于 Web 服务而言,提升可扩展性的主要途径是将耗时的同步工作改成异步处理,从而允许将这些工作"外包"给多个 Worker 去做,或者提前完成能够预知的部分. 异步机制与可扩展性 ...

  6. ajax优缺点及原理,Ajax实例解析,异步机制以及优缺点

    Ajax实例解析 1.Ajax读取一个xml文档并进行解析的实例: 服务器端(PHP): 客户端: var ajax = new XMLHttpRequest(); function sendMess ...

  7. JavaScript重难点解析5(对象高级、浏览器内核与事件循环模型(js异步机制))

    JavaScript重难点解析5(对象高级.浏览器内核与事件循环模型(js异步机制) 对象高级 对象创建模式 Object构造函数模式 对象字面量模式 工厂模式 自定义构造函数模式 构造函数+原型的组 ...

  8. 马蹄疾 | 详解 JavaScript 异步机制及发展历程(万字长文)

    本文从Event Loop.Promise.Generator.async await入手,系统的回顾 JavaScript 的异步机制及发展历程. 需要提醒的是,文本没有讨论 nodejs 的异步机 ...

  9. java同步和异步机制_JAVA学习过程中的知识——java多线程的同步和异步

    1.多线程和异步操作的异同 多线程和异步操作两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性.甚至有些时候我们就认为多线程和异步操作是等同的概念.但是,多线程和异步操作还是有一些区别的.而 ...

最新文章

  1. lnmp php编译参数,LAMP、LNMP环境编译参数查询
  2. Android面试宝典
  3. 在线实时大数据平台Storm本地模式运行的一个小发现
  4. python中的请求方法_http协议的9种请求方法
  5. 2017年第八届蓝桥杯 - 省赛 - C/C++大学A组 - A. 迷宫
  6. [luogu 4292][bzoj 1758][WC2010] 重建计划(点分治 + dp + 单调队列优化 + 启发式合并)
  7. 阿里腾讯前端一面小结
  8. 小练习-----银行提款机系统
  9. 第二次作业+105032014037
  10. Linux MySQL主主复制(Replication)(MySQL数据双向同步)配置
  11. 学习http only cookie以及javascript创建cookie的方式
  12. Java项目:SSM网上超市购物商城管理系统
  13. Ds918 ds3615 ds3617区别_苹果678有什么区别
  14. 解决win7无法共享问题
  15. html如何给table加水印,如何在Excel表格中添加水印
  16. 【渝粤教育】国家开放大学2019年春季 24建筑工程管理与实务 参考试题
  17. 浅谈 - 技术人员为什么更喜欢进行人身攻击?
  18. 网站的页面该如何去设计与布局
  19. 1010: 求圆的周长和面积 ZZULIOJ
  20. <img>标签上title属性与alt属性的区别

热门文章

  1. nrm:安装与配置记录
  2. 图文列表+富文本解析+折线图示例小程序模板
  3. 与梦城Typecho博客数据站+API站
  4. 织梦众大云采集插件v9.7
  5. WPF入门教程系列(二) 深入剖析WPF Binding的使用方法
  6. Magento教程 12:Magento快速上传大量商品的方法
  7. 如何使用社会化媒体网络建立个人品牌(国外篇)
  8. 使用 jQuery Mobile 与 HTML5 开发 Web App (十一) —— jQuery Mobile 事件详解
  9. shell编程:对话 UNIX: 更多 shell 脚本技术
  10. ubuntu上安装 ibus Google拼音输入法