利用SemaphoreSlim類別來進行async/await非同步工作排程
非同步程式如果不是用在處理大量的事情,似乎就沒有存在的意義了。之前在處理非同步且大量工作的作法,是真的使用System.Threading.Tasks.Task.Factory.StartNew去硬刻出每一個步驟,這樣的缺點是會導致程式碼又臭又長,今日,我們可以使用SemaphoreSlim來幫我降低一下程式碼的複雜性,我大概以後都會靠SemaphoreSlim來幫我進行工作排程的控制了吧!
Console程式碼範例如下:
namespace SemaphoreSlimTest
{
class Program
{
//建立結果集收納處
private System.Collections.Generic.List<string> oResult = new System.Collections.Generic.List<string>();
//建立工作排程
private async System.Threading.Tasks.Task PushToTask(System.Collections.Generic.IList<string> oURLs)
{
System.Collections.Generic.List<System.Threading.Tasks.Task> oTasks = new System.Collections.Generic.List<System.Threading.Tasks.Task>();
System.Threading.SemaphoreSlim oControl = new System.Threading.SemaphoreSlim(oURLs.Count);
foreach (var cURL in oURLs)
{
await oControl.WaitAsync();
oTasks.Add(System.Threading.Tasks.Task.Run(async () =>
{
try
{
var oWC = new System.Net.WebClient();
string cTemp = await oWC.DownloadStringTaskAsync(new System.Uri(cURL));
oResult.Add(cTemp);
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex.ToString());
}
finally
{
oControl.Release();
}
}));
}
//最終等待
await System.Threading.Tasks.Task.WhenAll(oTasks);
//列印出結果
foreach (var item in oResult)
{
System.Console.Write(item);
}
}
//主控台
static void Main(string[] args)
{
//利用免費服務,傳回JSON字串
string[] oURL = {
"http://headers.jsontest.com/",
"http://echo.jsontest.com/name/john"
};
System.Console.WriteLine(@"/* STEP.A */");
var a = new Program();
var oObj = a.PushToTask(oURL);
System.Console.WriteLine(@"/* STEP.B */");
//這邊創造一個逼近處理臨界點的等待,讓結果出現隨機跳動
System.Threading.Thread.Sleep(320);
System.Console.WriteLine(@"/* STEP.C */");
System.Console.Read();
}
}
}
輸出結果範例:
延遲後比JSON回傳值還快!
JSON回傳值比延遲後還快!
相關參考:
- 非同步程式設計Async與Await
- 在泛型處理常式(ashx)中利用HttpTaskAsyncHandler來完成async/await之需求
- 再論具總量控管之.NET非同步工作排程模型
- 延伸參考:YOU'RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE;HttpClient因IDisposable反而引發連線資源耗盡(TIME_WAIT)問題
- HttpClient所引爆的Sockets Port耗盡問題