程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> [.NET] 利用 async & await 進行異步 IO 操作(整理中...),.net利用async

[.NET] 利用 async & await 進行異步 IO 操作(整理中...),.net利用async

編輯:關於.NET

[.NET] 利用 async & await 進行異步 IO 操作(整理中...),.net利用async


利用 async & await 進行異步 IO 操作

  可以使用異步函數訪問文件。使用異步功能,可以調用異步方法,而不使用回調或拆分您在多個方法或 lambda 表達式中的代碼。 若要使同步代碼異步,則調用異步方法而不是一個同步方法並添加幾個關鍵字到代碼中。

  對文件操作使用異步特性:

  • 異步特性有利於應用程序的響應能力更強。因為一個操作的 UI 線程可以執行其他工作。 如果 UI 線程必須執行需要很長時間的代碼(例如,超過 50 毫秒),UI 可以凍結,直到 I/O 完成的,並且用戶界面線程可以重新處理鍵盤和鼠標輸入和其他操作。

  • 異步特性有利於通過減少對線程的需要增強 ASP.NET 和其他的可伸縮性基於服務器的應用程序。 如果應用程序使用專用線程上每個響應,並且一次兩個請求同時處理,則有線程是必需的。 在等待期間,異步操作通常不需要使用線程。 它們簡要使用現有的 I/O 完成線程在末尾。

  • 文件訪問操作的延遲在本地也許非常低,但是,我們可以考慮一下文件在非本地時進行的操作。 例如,文件可能會存放位於遠程的服務器。

  • 使用異步額外增加的開銷很小。

  • 異步任務可以並行運行。

 

使用 FileStream 類

  示例使用 FileStream 類,它具有一個選項導致異步 I/O 發生在操作系統級別。使用此選項,您可以避免在許多情況下阻止線程池線程。 若要啟用此選項,則指定 useAsync=true 或在構造函數中 options=FileOptions.Asynchronous 參數調用。

  不能對 StreamReader 和 StreamWriter 的此選項,如果直接通過指定文件路徑打開這些文件。 但是,您可以使用此選項,則提供自己 FileStream 類打開的 Stream。 請注意,異步調用是比在 UI app,即使線程池線程阻塞,在等待期間,因為用戶界面線程未阻止。

 

編寫文本

  下面的示例寫入文本到文件。 在每個請等待語句,則此方法會立即退出。 當文件 I/O 完成時,方法以等待語句後面的語句。 請注意"修飾符在使用等待語句方法的定義。

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。 不同於在前面的示例中,等待的計算生成值。ReadAsync 方法返回 Task<Int32>,因此,等待的計算生成一個 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

  下面的示例通過編寫 10 個文本文件演示並行處理。 對於每個文件,WriteAsync 方法返回然後添加到任務列表的任務。文件時,在處理為所有完成的任務時,await Task.WhenAll(tasks); 語句退出方法並在方法中恢復。

  在任務完成後,該示例以 finally 的所有 FileStream 實例塊。 如果每 FileStream 在 using 語句中創建的,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,來在中途取消操作。 

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved