并行任務(wù)(Task)以及基于Task的異步編程(asynchronously)在.NET Framework早已使用多年,而在微軟新推出的.NET Core 平臺下也有相同功能的實(shí)現(xiàn),本文將通過.NET Core WebAPI怔檩,介紹使用Task.result的同步編程以及使用await的異步編程模型署照。
Task.Result
Result方法可以返回Task執(zhí)行后的結(jié)果棺弊,如下代碼:
[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輸出值谷婆,會造成當(dāng)前API線程阻塞等待到task執(zhí)行完成后再繼續(xù)進(jìn)行肩杈。可以通過下面代碼來證明媒区,get方法有一個線程,調(diào)用一個新線程執(zhí)行task(taskcaller)掸犬,在執(zhí)行task時候由于需要等待task的執(zhí)行結(jié)果袜漩,此時get方法的執(zhí)行線程等待中,直到result結(jié)果輸出湾碎,此線程繼續(xù)完成方法宙攻。
[HttpGet]
public string Get()
{
var info = string.Format("api執(zhí)行線程:{0}", Thread.CurrentThread.ManagedThreadId);
var infoTask = TaskCaller().Result;
var infoTaskFinished = string.Format("api執(zhí)行線程(task調(diào)用完成后):{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 執(zhí)行線程:{0}", Thread.CurrentThread.ManagedThreadId);
}
代碼執(zhí)行流程
輸出結(jié)果如下
async & await
如果使用await,在調(diào)用 await taskcall() 時不會阻塞get主方法線程介褥,主方法線程會被釋放座掘,新的線程執(zhí)行完成task后繼續(xù)執(zhí)行await后的代碼減少線程切換開銷,而之前的線程則空閑了柔滔。
[HttpGet]
public async Task<string> Get()
{
var info = string.Format("api執(zhí)行線程:{0}", Thread.CurrentThread.ManagedThreadId);
var infoTask = await TaskCaller();
var infoTaskFinished = string.Format("api執(zhí)行線程(task調(diào)用完成后):{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 執(zhí)行線程:{0}", Thread.CurrentThread.ManagedThreadId);
}
代碼執(zhí)行流程
輸出結(jié)果如下
總結(jié)
Task.result 與 await關(guān)鍵字 具有類似的功能可以獲取到任務(wù)的返回值溢陪,但是本質(zhì)上Task.result會讓外層函數(shù)執(zhí)行線程阻塞直到任務(wù)執(zhí)行完成,而使用await關(guān)鍵字外層函數(shù)線程則不會阻塞睛廊,而是通過任務(wù)執(zhí)行線程來執(zhí)行await后的代碼形真。