Asp.net

在 IHttpAsyncHandler 中使用 Task 或 async/await

  • March 14, 2014

自從我想添加執行緒開始編寫 ASP.NET 應用程序以來,有 3 種簡單的方法可以在我的 ASP.NET 應用程序中完成執行緒:

  • 使用System.Threading.ThreadPool.
  • 使用自定義委託並呼叫其BeginInvoke方法。
  • 在類的幫助下使用自定義執行緒System.Threading.Thread

前兩種方法提供了一種為您的應用程序啟動工作執行緒的快速方法。但不幸的是,它們會損害應用程序的整體性能,因為它們使用 ASP.NET 用來處理 HTTP 請求的同一池中的執行緒

然後我想用一個新的 Task 或者 async/await 來寫IHttpAsyncHandler. 你可以找到一個例子是 Drew Marsh 在這裡解釋的:https ://stackoverflow.com/a/6389323/261950

我的猜測是,使用 Task 或 async/await 仍然會消耗 ASP.NET 執行緒池中的執行緒,並且出於明顯的原因我不想要。

您能否告訴我是否可以在後台執行緒上使用 Task (async/await),例如使用System.Threading.Thread而不是執行緒池

在此先感謝您的幫助。

托馬斯

這幾天一直在網上找資料。讓我總結一下我到目前為止的發現:

ASP.NET 執行緒池事實

  • 正如 Andres 所說:當 async/await 不會消耗額外的 ThreadPool 執行緒時?僅在您使用 BCL 非同步方法的情況下。使用 IOCP 執行緒執行 IO 綁定操作。
  • Andres**繼續_ _ _

但據我所知,您無法選擇是否要使用 IOCP 執行緒,並且正確實現 threadPool 是不值得的。我懷疑有人做得更好,已經存在。

  • ASP.NET 使用公共語言執行時 (CLR) 執行緒池中的執行緒來處理請求。只要執行緒池中有可用的執行緒,ASP.NET 就可以毫無問題地分派傳入的請求。
  • 非同步delegates使用 ThreadPool 中的執行緒。

什麼時候應該開始考慮實現非同步執行?

  • 當您的應用程序執行相對冗長的 I/O 操作(數據庫查詢、Web 服務呼叫和其他 I/O 操作)時
  • 如果你想做 I/O 工作,那麼你應該使用 I/O 執行緒(I/O 完成埠),特別是你應該使用你正在使用的任何庫類支持的非同步回調。Begin他們的名字以and開頭End
  • 如果請求在計算上處理起來很便宜,那麼並行性可能是不必要的成本。
  • 如果傳入的請求率很高,那麼增加更多的並行性可能不會帶來什麼好處,實際上可能會降低性能,因為傳入的工作率可能高到足以讓 CPU 保持忙碌。

我應該創建新執行緒嗎?

  • 避免像避免瘟疫一樣創建新執行緒。
  • 如果您實際上排隊了足夠多的工作項以防止 ASP.NET 處理進一步的請求,那麼您應該餓死執行緒池!如果您實際上同時執行數百個 CPU 密集型操作,那麼當機器已經超載時,讓另一個工作執行緒來服務 ASP.NET 請求會有什麼好處。

TPL 呢?

  • TPL 可以適應在程序中使用可用資源。如果伺服器已經載入,TPL 可以使用最少一個工作人員並向前推進。如果伺服器大部分是免費的,它們可以增長到使用執行緒池可以騰出的盡可能多的工作人員。
  • 任務使用執行緒池執行緒來執行。

參考

  • <http://msdn.microsoft.com/en-us/magazine/cc163463.aspx>
  • <http://blogs.msdn.com/b/pfxteam/archive/2010/02/08/9960003.aspx>
  • <https://stackoverflow.com/a/2642789/261950>

這種情況是Task,asyncawait真正閃耀的地方。這是相同的範例,經過重構以充分利用async(它還使用我的AsyncEx庫中的一些幫助程序類來清理映射程式碼):

// First, a base class that takes care of the Task -&gt; IAsyncResult mapping.
// In .NET 4.5, you would use HttpTaskAsyncHandler instead.
public abstract class HttpAsyncHandlerBase : IHttpAsyncHandler
{
   public abstract Task ProcessRequestAsync(HttpContext context);

   IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
   {
       var task = ProcessRequestAsync(context);
       return Nito.AsyncEx.AsyncFactory.ToBegin(task, cb, extraData);
   }

   void EndProcessRequest(IAsyncResult result)
   {
       Nito.AsyncEx.AsyncFactory.ToEnd(result);
   }

   void ProcessRequest(HttpContext context)
   {
       EndProcessRequest(BeginProcessRequest(context, null, null));
   }

   public virtual bool IsReusable
   {
       get { return true; }
   }
}

// Now, our (async) Task implementation
public class MyAsyncHandler : HttpAsyncHandlerBase
{
   public override async Task ProcessRequestAsync(HttpContext context)
   {
       using (var webClient = new WebClient())
       {
           var data = await webClient.DownloadDataTaskAsync("http://my resource");
           context.Response.ContentType = "text/xml";
           context.Response.OutputStream.Write(data, 0, data.Length);
       }
   }
}

(如程式碼中所述,.NET 4.5 有一個HttpTaskAsyncHandler類似於我們HttpAsyncHandlerBase上面的)。

真正酷的是它在執行後台操作時async不佔用任何執行緒:

  • 一個 ASP.NET 請求執行緒啟動請求,並開始使用WebClient.
  • 在下載過程中,await實際從方法中返回async,離開請求執行緒。該請求執行緒返回到執行緒池 - 留下 0()個執行緒為該請求提供服務。
  • 當下載完成時,該async方法在請求執行緒上恢復。該請求執行緒僅用於編寫實際響應。

這是最佳的執行緒解決方案(因為需要一個請求執行緒來編寫響應)。

原始範例還以最佳方式使用執行緒 - 就執行緒而言,它與async基於 - 的程式碼相同。但 IMO 的async程式碼更容易閱讀。

如果您想了解更多關於的資訊,我的部落格上async有一篇介紹文章。

引用自:https://stackoverflow.com/questions/9225420