[.NET] 利用 async & await 进行异步 IO 操作(整理中...)_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > [.NET] 利用 async & await 进行异步 IO 操作(整理中...)

[.NET] 利用 async & await 进行异步 IO 操作(整理中...)

 2016/11/23 5:30:30  反骨仔(二五仔)  程序员俱乐部  我要评论(0)
  • 摘要:利用async&await进行异步IO操作【博主】反骨仔【出处】http://www.cnblogs.com/liqingwen/p/6082673.html序上次,博主通过《利用async&await的异步编程》这篇点睛之作初步介绍了async&await的基本用法及异步的控制流和一些其它的东西;接着,博主通过《怎样使用async&await一步步将同步代码转换为异步编程》这篇随笔诱导大家如何一步步转换自己的同步代码;今天,我们来一起看看如何用异步进行IO操作
  • 标签:.net net 利用 操作 异步

利用 async & await 进行异步 IO 操作

【博主】反骨仔  【出处】http://www.cnblogs.com/liqingwen/p/6082673.html   

class="sentence SentenceHover" data-guid="987b5829f8cd58dfa51a2e2f1021705f" data-source="You can use the <span class="mtpsTagOuterHtml" >Async feature to access files.">序  

  Studio 2012.">上次,博主通过《利用 async & await 的异步编程》这篇点睛之作初步介绍了 async & await 的基本用法及异步的控制流和一些其它的东西;  

  接着,博主通过《怎样使用 async & await 一步步将同步代码转换为异步编程》这篇随笔诱导大家如何一步步转换自己的同步代码;

  今天,我们来一起看看如何用异步进行 IO 操作。

 

目录

 

使用异步特性实现 IO 操作的意义

  • thread that launches the operation can perform other work.">异步特性有利于增强应用程序的响应能力。因为一个操作的 UI 线程可以执行其他工作。如果 UI 线程需要执行较长时间的代码(如,> 50ms),UI 会阻塞到 I/O 完成,这时用户界面线程才可以重新处理键盘、鼠标输入和其他操作。
  • 文件访问操作的延迟在本地也许非常低,但是,我们可以考虑一下文件在非本地时进行的操作。例如,文件可能会存放位于远程的服务器。
  • 使用异步额外增加的开销很小。
  • 异步任务可以并行运行。

 

使用 FileStream 

has an option that causes asynchronous I/O to occur at the operating system level.">  示例使用 FileStream 类,它具有一个 option 导致异步 I/O 发生在操作系统级别。many cases.">使用此 option,您可以避免在许多情况下阻塞线程池线程。若要启用该 option,则指定 useAsync = true 或在构造函数中进行参数调用。

  不能设置 StreamReader 和 StreamWriter 的 option,如果直接通过指定文件路径打开这些文件。但是,您如果想使用该 option,则提供自己 FileStream 类打开的 Stream。 请注意,异步调用是在 UI app,即使线程池线程阻塞,在 await 期间,用户界面线程也不会被阻塞。

 

编写文本

  下面的示例是将文本写入到文件。在每个 await 语句中,都会立即退出。当文件 I/O 完成时,方法会执行 await 语句后面的语句。请注意异步修饰符在使用 await 语句方法的定义。

1         private async void btnWrite_Click(object sender, RoutedEventArgs e)
2         {
3             await WriteTextAsync();
4         }
btnWrite_Click

 

 1         /// <summary>
 2         /// 异步写入文件
 3         /// </summary>
 4         /// <returns></returns>
 5         private async Task WriteTextAsync()
 6         {
 7             var path = $"temp.txt";
 8             var content = Guid.NewGuid().ToString();
 9 
10             using (var fs = new FileStream(path,
11                 FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, bufferSize: 4096, useAsync: true))
12             {
13                 var buffer = Encoding.UTF8.GetBytes(content);
14 
15                 //var writeTask = fs.WriteAsync(buffer, 0, buffer.Length);
16                 //await writeTask;
17                 await fs.WriteAsync(buffer, 0, buffer.Length);
18             }
19         }

  行号 17 的语句可以修改为:

1   //await fs.WriteAsync(buffer, 0, buffer.Length);
2   //可以改为
3   var writeTask = fs.WriteAsync(buffer, 0, buffer.Length);
4   await writeTask;

  第一个语句(行号 1)返回任务并导致进程的文件。使用等待的第二个语句(行号3、4)导致方法立即退出并返回其他任务。当随后处理的文件完成时,执行回 await 的语句。 

 

读取文本

  下面的示例是从文件中读取文本。将文本缓冲区的内容放入 StringBuilder。不同于在前面的示例,会不断 await 一个读取的长度值。ReadAsync 方法返回 Task<Int32>,即 Task<int>,因此,等待的计算生成一个 Int32 值(numRead),在操作完成之后。

 1         /// <summary>
 2         /// 异步读取文本
 3         /// </summary>
 4         /// <param name="fileName"></param>
 5         /// <returns></returns>
 6         private async Task<string> ReadTextAsync(string fileName)
 7         {
 8             using (var fs = new FileStream(fileName,
 9                 FileMode.OpenOrCreate, FileAccess.Read, FileShare.None, bufferSize: 4096, useAsync: true))
10             {
11                 var sb = new StringBuilder();
12                 var buffer = new byte[0x1000];  //十六进制 等于十进制的 4096
13                 var readLength = 0;
14 
15                 while ((readLength = await fs.ReadAsync(buffer, 0, buffer.Length)) != 0)
16                 {
17                     var text = Encoding.UTF8.GetString(buffer, 0, readLength);
18                     sb.Append(text);
19                 }
20 
21                 return sb.ToString();
22             }
23         }

 

 1         private async void btnRead_Click(object sender, RoutedEventArgs e)
 2         {
 3             var fileName = $"temp.txt";
 4             if (!File.Exists(fileName))
 5             {
 6                 Debug.WriteLine($"文件找不到:{fileName}");
 7                 return;
 8             }
 9 
10             try
11             {
12                 var content = await ReadTextAsync(fileName);
13                 Debug.WriteLine(content);
14             }
15             catch (Exception ex)
16             {
17                 Debug.WriteLine(ex.Message);
18             }
19         }
btnRead_Click

 

并行异步 I/O

  下面的示例通过编写多个文本文件进行演示并行处理。对于每个文件,WriteAsync 方法返回后将被添加到任务列表的集合中。在处理完成所有的任务时,await Task.WhenAll(tasks); 语句将退出方法并恢复执行。

instances in a <span class="input">finally block after the tasks are complete.">  在任务完成后,进入 finally 块的将所有 FileStream 实例进行清理回收。created in a <span class="input">using statement, the <strong>FileStream</strong> might be disposed of before the task was complete.">如果直接在 using 语句中创建 FileStream 实例,则 FileStream 实例可能在任务完成之前就被处理。

  【注意】所有性能提高几乎完全是异步并行处理。异步的优点是它不会占用多个线程,也就是说,它不会占用用户界面线程。

 1         /// <summary>
 2         /// 异步写入多个文件
 3         /// </summary>
 4         /// <param name="folder"></param>
 5         /// <returns></returns>
 6         private async Task WriteMultiTextAsync(string folder)
 7         {
 8             var tasks = new List<Task>();
 9             var fileStreams = new List<FileStream>();
10 
11             try
12             {
13                 for (int i = 1; i <= 10; i++)
14                 {
15                     var fileName = Path.Combine(folder, $"{i}.txt");
16                     var content = Guid.NewGuid().ToString();
17                     var buffer = Encoding.UTF8.GetBytes(content);
18 
19                     var fs = new FileStream(fileName,
20         FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, bufferSize: 4096, useAsync: true);
21                     fileStreams.Add(fs);
22 
23                     var writeTask = fs.WriteAsync(buffer, 0, buffer.Length);
24                     tasks.Add(writeTask);
25                 }
26 
27                 await Task.WhenAll(tasks);
28             }
29             finally
30             {
31                 foreach (var fs in fileStreams)
32                 {
33                     fs.Close();
34                     fs.Dispose();
35                 }
36             }
37         }

 

 1         private async void btnWriteMulti_Click(object sender, RoutedEventArgs e)
 2         {
 3             var folder = $"temp";
 4 
 5             if (!Directory.Exists(folder))
 6             {
 7                 Directory.CreateDirectory(folder);
 8             }
 9 
10             await WriteMultiTextAsync(folder);
11         }
btnWriteMulti_Click

  在使用 WriteAsync 和 ReadAsync 方案时,你可以指定 CancellationToken,来在中途取消操作。 

 

  点我 Demo 下载

 

同系列的随笔

  • 利用 async & await 的异步编程

  • 怎样使用 async & await 一步步将同步代码转换为异步编程

  • 走进异步编程的世界 - 开始接触 async/await

  • 走进异步编程的世界 - 剖析异步方法(上)

  • 走进异步编程的世界 - 剖析异步方法(下)

  • 走进异步编程的世界 - 在 GUI 中执行异步操作

 

 

发表评论
用户名: 匿名