利用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(WebClient因實作IDisposable反而引發連線資源耗盡(TIME_WAIT)問題

System.Threading.SemaphoreSlim System.Threading.Tasks.Task aSync aWait