首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET 非同步機制深度解析 (四):Stream 非同步讀寫 — APM 模式、匿名方法與 Lambda 表達式實戰

     編輯:關於.NET

所有繼承 System.IO.Stream 的類別 (FileStream、NetworkStream、CryptoStream 等) 均支援標準 APM (Asynchronous Programming Model) 非同步讀寫:BeginRead/EndRead、BeginWrite/EndWrite。本文從同步基準開始,逐步演示 APM、匿名方法、Lambda 三種寫法,並說明關鍵建構子參數 useAsync=true 的效能影響。

同步基準:FileStream 讀取

using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 20480, false))
{
    byte[] buffer = new byte[5];
    int read;
    var sb = new StringBuilder();
    while ((read = fs.Read(buffer, 0, buffer.Length)) > 0)
        sb.Append(Encoding.ASCII.GetString(buffer, 0, read));
    Console.WriteLine(sb);
}

APM 標準模式:BeginRead/EndRead

關鍵:建構子最後一個參數 useAsync=true (或 FileOptions.Asynchronous),否則內部仍同步模擬,反而降低效能。

FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 20480, true);
byte[] buffer = new byte[5];
fs.BeginRead(buffer, 0, buffer.Length, OnReadComplete, fs);

void OnReadComplete(IAsyncResult ar)
{
    FileStream fs = (FileStream)ar.AsyncState;
    int read = fs.EndRead(ar);
    Console.Write(Encoding.ASCII.GetString(buffer, 0, read));
    if (read > 0)
        fs.BeginRead(buffer, 0, buffer.Length, OnReadComplete, fs);
    else
        fs.Close(); // 手動釋放,不可 using
}

C# 2.0 匿名方法簡化狀態傳遞

編譯器自動將區域變數捕獲為閉包類別欄位,免去手動在 AsyncState 傳遞 FileStream。

FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 20480, true);
byte[] buffer = new byte[5];
AsyncCallback callback = null;
callback = delegate(IAsyncResult ar)
{
    int read = fs.EndRead(ar);
    Console.Write(Encoding.ASCII.GetString(buffer, 0, read));
    if (read > 0) fs.BeginRead(buffer, 0, buffer.Length, callback, null);
    else fs.Close();
};
fs.BeginRead(buffer, 0, buffer.Length, callback, null);

注意:必須先宣告 AsyncCallback callback = null;,否則編譯器報「使用未指派區域變數」。

C# 3.0 Lambda 表達式更簡潔

FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 20480, true);
byte[] buffer = new byte[5];
AsyncCallback callback = null;
callback = ar =>
{
    int read = fs.EndRead(ar);
    Console.Write(Encoding.ASCII.GetString(buffer, 0, read));
    if (read > 0) fs.BeginRead(buffer, 0, buffer.Length, callback, null);
    else fs.Close();
};
fs.BeginRead(buffer, 0, buffer.Length, callback, null);

非同步寫入:BeginWrite/EndWrite

FileStream fs = new FileStream("out.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 20480, true);
byte[] data = Encoding.ASCII.GetBytes(Console.ReadLine());
fs.BeginWrite(data, 0, data.Length, ar => { fs.EndWrite(ar); fs.Close(); }, null);

超時處理提醒

Stream.ReadTimeout/WriteTimeout 在基類預設不支援,直接拋出 InvalidOperationException,需自行實作計時器或使用 CancellationToken (現代模式)。

下一篇將深入 IAsyncResult 核心介面與 AsyncWaitHandle 同步原語應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved