【不少初学者的疑问】html
为什么做为web api这样的自然的并发应用,还须要在controller的action上声明使用async这些呢?web
<参考解答>api
在 web 服务器上,.NET Framework 维护用于处理 ASP.NET 请求的线程池。 当请求到达时,将调度池中的线程以处理该请求。 若是以同步方式处理请求,则处理请求的线程将在处理请求时处于繁忙状态,而且该线程没法处理其余请求。
若是请求发出须要两秒钟时间才能完成的 web 服务调用,则该请求将须要两秒钟,不管是同步执行仍是异步执行。 可是,在异步调用期间,线程在等待第一个请求完成时不会被阻止响应其余请求。 所以,当有多个并发请求调用长时间运行的操做时,异步请求会阻止请求队列和线程池的增加。服务器
[注]总的来讲,对单个客户端请求来讲,它感觉到的速度,响应时间并无由于使用异步而提高,但对整个服务器来讲,由于线程在异步场景下等待的同时还在服务其它的线程,所以线程数不会增加太快,进而不会轻易达到繁忙状态。并发
【给出一个本身写的分析代码】异步
using ConfigLab.Comp; using ConfigLab.Comp.HttpRequestTools.HttpClient; using ConfigLab.Comp.MetaData; using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; using System.Web.Hosting; using System.Web.Http; namespace ConfigLab.WebApiProject.Controllers { /// <summary> /// 功能简介:web api中的异步接口体会 /// 建立时间:2020-8-23 /// 建立人:pcw /// 备注:若是不须要全部接口有一个默认的 /api/*中的api这段,须要自行修改RouteConfig.cs中的路由设置 /// </summary> public class CommonAPIController : ApiController { /// <summary> /// https://localhost:44305/CommonAPI/getTest1?userid=u001 /// </summary> /// <param name="userid"></param> /// <returns></returns> public string getTest(string userid) { return $"test1_result(from web api):userid={userid}"; } /// <summary> /// https://localhost:44305/CommonAPI/getTest2 /// 参数:userid=u002&optype=add /// </summary> /// <param name="data"></param> /// <returns></returns> [HttpPost] public string postTest([FromBody] userActin data) { return $"test2_result(from web api):userid={data.userid},optype={data.optype}"; } /// <summary> /// 请求地址:https://localhost:44305/CommonAPI/postListByAsync /// 参数:userid=u002&optype=add /// 返回:多个网站的返回值 /// </summary> /// <param name="data"></param> /// <returns></returns> public async Task<List<ResponseResult>> postListByAsync([FromBody] userActin data) { List<ResponseResult> listResult = new List<ResponseResult>(); HttpClientAssisterAsync httpAssist = new HttpClientAssisterAsync();//介绍(https://www.cnblogs.com/taohuadaozhu/p/13548266.html),Nuget 搜索安装: ConfigLab.Comp便可使用 Task<ResponseResult> tsk_rrs = httpAssist.SendRequestByGet("http://www.baidu.com"); await tsk_rrs; listResult.Add(tsk_rrs.Result); tsk_rrs = httpAssist.SendRequestByGet("http://www.ifeng.com"); await tsk_rrs; listResult.Add(tsk_rrs.Result); return listResult; } /// <summary> /// 请求地址:https://localhost:44305/CommonAPI/SaveFile?projectId=p001&userid=u003 /// 附加参数:文件流 /// </summary> /// <param name="projectId"></param> /// <param name="userid"></param> /// <returns></returns> public async Task<RunResult> SaveFile(string projectId, string userid) { RunResult rrs = new RunResult(); if (!Request.Content.IsMimeMultipartContent()) { //throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); return new RunResult() { RunCode = -1, RunMsg = "HttpStatusCode.UnsupportedMediaType" }; } //string root = Path.Combine(HostingEnvironment.MapPath(ConfigurationManager.AppSettings["FileStorePath"]), DateTime.Now.ToShortDateString(), projectId); string root = Path.Combine(ConfigurationManager.AppSettings["FileStorePath"], DateTime.Now.ToShortDateString(), projectId); if (!Directory.Exists(root)) Directory.CreateDirectory(root); MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(root); try { await Request.Content.ReadAsMultipartAsync(provider); return new RunResult() { RunCode = 0, RunMsg = "" }; } catch (Exception ex) { rrs.RunCode = -2; rrs.RunMsg = $"获取客户端上传的文件流失败,ex.msg={ex.Message},ex.stacktrace={ex.StackTrace}"; } return rrs; } } /// <summary> /// 测试用的post参数对象 /// </summary> public class userActin { public string userid { get; set; } public string optype { get; set; } } }