[.NET] 利用 async & await 進行非同步 IO 操作

来源:http://www.cnblogs.com/liqingwen/archive/2016/11/23/6082673.html
-Advertisement-
Play Games

利用 async & await 進行非同步 IO 操作 【博主】反骨仔 【出處】http://www.cnblogs.com/liqingwen/p/6082673.html 序 上次,博主通過《利用 async & await 的非同步編程》這篇點睛之作初步介紹了 async & await 的基本 ...


利用 async & await 進行非同步 IO 操作

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

序  

  上次,博主通過《利用 async & await 的非同步編程》這篇點睛之作初步介紹了 async & await 的基本用法及非同步的控制流和一些其它的東西;  

  接著,博主通過《怎樣使用 async & await 一步步將同步代碼轉換為非同步編程》這篇隨筆誘導大家如何一步步轉換自己的同步代碼;

  今天,我們來一起看看如何用非同步進行 IO 操作。

 

使用非同步特性實現 IO 操作的意義

  • 非同步特性有利於增強應用程式的響應能力。因為一個操作的 UI 線程可以執行其他工作。如果 UI 線程需要執行較長時間的代碼(如,> 50ms),UI 會阻塞到 I/O 完成,這時用戶界麵線程才可以重新處理鍵盤、滑鼠輸入和其他操作。
  • 文件訪問操作的延遲在本地也許非常低,但是,我們可以考慮一下文件在非本地時進行的操作。例如,文件可能會存放位於遠程的伺服器。
  • 使用非同步額外增加的開銷很小。
  • 非同步任務可以並行運行。

 

使用 FileStream 

  示例使用 FileStream 類,它具有一個 option 導致非同步 I/O 發生在操作系統級別。使用此 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); 語句將退出方法並恢復執行。

  在任務完成後,進入 finally 塊的將所有 FileStream 實例進行清理回收。如果直接在 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 下載

 

同系列的隨筆

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • linux shell可以識別4種不同類型的引字元號: 單引號字元' 雙引號字元" 反斜杠字元\ 反引號字元` 1. 單引號 ( '' )# grep Susan phonebook Susan Goldberg 403-212-4921 Susan Topple 212-234-2343 如果我們 ...
  • 在Ubuntu中第一次使用VIM編輯器發現好強大,打算在Win7中安裝,其中遇到一些小問題,下邊介紹詳細的安裝過程和遇到的問題。 1-安裝 首先發現Github中有一款中意的作者,並且他開源的基本插件都集合了。 地址:https://github.com/DemonCloud/Aix-Vim(下載地 ...
  • web.config <configuration> <connectionStrings> <add name="constr" connectionString="server=.\sqlexpress;database=db2016;uid=sa;pwd=123;" /> <add name= ...
  • Public Class Profile Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As Stri ...
  • 現在流行的系統一般都採用依賴註入的實現方式,利用DI容器來直接獲取所用到的類/介面的實例。.net core也一樣採用DI的方式,提供了DI容器的介面IServiceCollection,並提供了基於該介面的預設實現ServiceCollection。 這樣我們就可以不再像以前一樣,需要引入第三方的 ...
  • 1.界面 <UserControl x:Class="HKDCMS.Client.Demo.UIViews.UIControls.AboutUsControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml ...
  • In Windows 8 & 10, you have to right-click devenv.exe and select "Troubleshoot compatibility". 轉自 http://stackoverflow.com/questions/12257110/can-you- ...
  • 註冊的伺服器和中間件共同構成了ASP.NET Core用於處理請求的管道, 這樣一個管道是在我們啟動作為應用宿主的WebHost時構建出來的。要深刻瞭解這個管道是如何被構建出來的,我們就必須對WebHost和它的創建者WebHostBuilder這個重要的對象具有深刻的理解。[ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...