並行任務(Task)以及基於Task的異步編程(asynchronously)在.NET Framework早已使用多年,而在微軟新推出的.NET Core 平台下也有相同功能的實現,本文將通過.NET Core WebAPI,介紹使用Task.result的同步編程以及使用await的異步編程模型。
Task.Result
Result方法可以返回Task執行后的結果,如下代碼:
[HttpGet]
public static async Task<JObject> GetJsonAsync(Uri uri)
{
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri);
return JObject.Parse(jsonString);
}
}
public class MyController : ApiController
{
public string Get()
{
var jsonTask = GetJsonAsync(...);
return jsonTask.Result.ToString();
}
}
但是如果在ASP.NET Core的webapi中使用result方法來獲取task輸出值,會造成當前API線程阻塞等待到task執行完成后再繼續進行。可以通過下面代碼來證明,get方法有一個線程,調用一個新線程執行task(taskcaller),在執行task時候由於需要等待task的執行結果,此時get方法的執行線程等待中,直到result結果輸出,此線程繼續完成方法。
[HttpGet]
public string Get()
{
var info = string.Format("api執行線程:{0}", Thread.CurrentThread.ManagedThreadId);
var infoTask = TaskCaller().Result;
var infoTaskFinished = string.Format("api執行線程(task調用完成后):{0}", Thread.CurrentThread.ManagedThreadId);
return string.Format("{0},{1},{2}", info, infoTask, infoTaskFinished);
}
private async Task<string> TaskCaller()
{
await Task.Delay(500);
return string.Format("task 執行線程:{0}", Thread.CurrentThread.ManagedThreadId);
}
代碼執行流程

輸出結果如下

async & await
如果使用await,在調用 await taskcall() 時不會阻塞get主方法線程,主方法線程會被釋放,新的線程執行完成task后繼續執行await后的代碼減少線程切換開銷,而之前的線程則空閑了。
[HttpGet]
public async Task<string> Get()
{
var info = string.Format("api執行線程:{0}", Thread.CurrentThread.ManagedThreadId);
var infoTask = await TaskCaller();
var infoTaskFinished = string.Format("api執行線程(task調用完成后):{0}", Thread.CurrentThread.ManagedThreadId);
return string.Format("{0},{1},{2}", info, infoTask, infoTaskFinished);
}
private async Task<string> TaskCaller()
{
await Task.Delay(500);
return string.Format("task 執行線程:{0}", Thread.CurrentThread.ManagedThreadId);
}
代碼執行流程

輸出結果如下

總結
Task.result 與 await關鍵字 具有類似的功能可以獲取到任務的返回值,但是本質上Task.result會讓外層函數執行線程阻塞直到任務執行完成,而使用await關鍵字外層函數線程則不會阻塞,而是通過任務執行線程來執行await后的代碼。
