为什么要创buildasynchronousWebAPI操作而不是同步?

我在创build的Web API中执行以下操作:

// GET api/<controller> [HttpGet] [Route("pharmacies/{pharmacyId}/page/{page}/{filter?}")] public CartTotalsDTO GetProductsWithHistory(Guid pharmacyId, int page, string filter = null ,[FromUri] bool refresh = false) { return delegateHelper.GetProductsWithHistory(CustomerContext.Current.GetContactById(pharmacyId), refresh); } 

对这个web服务的调用是通过一个jQuery的Ajax调用完成的:

 $.ajax({ url: "/api/products/pharmacies/<%# Farmacia.PrimaryKeyId.Value.ToString() %>/page/" + vm.currentPage() + "/" + filter, type: "GET", dataType: "json", success: function (result) { vm.items([]); var data = result.Products; vm.totalUnits(result.TotalUnits); } }); 

我见过一些开发人员用这种方式实现了前面的操作:

 // GET api/<controller> [HttpGet] [Route("pharmacies/{pharmacyId}/page/{page}/{filter?}")] public async Task<CartTotalsDTO> GetProductsWithHistory(Guid pharmacyId, int page, string filter = null ,[FromUri] bool refresh = false) { return await Task.Factory.StartNew(() => delegateHelper.GetProductsWithHistory(CustomerContext.Current.GetContactById(pharmacyId), refresh)); } 

不过要说,GetProductsWithHistory()是一个相当长的操作。 鉴于我的问题和上下文,如何使webAPI操作asynchronous好处我?

在你的具体例子中,操作并不是asynchronous的,所以你在做的是asynchronous同步。 你只是释放一个线程并阻止另一个线程。 没有理由,因为所有线程都是线程池线程(与GUI应用程序不同)。

在我关于“asynchronous同步”的讨论中,我强烈build议如果你有一个内部同步实现的API,你不应该公开一个简单地将同步方法包装在Task.Run的asynchronous对象。

从我应该公开asynchronous方法的同步包装?

然而,当WebAPI调用async地方有一个实际的asynchronous操作(通常是I / O),而不是阻塞一个坐着的线程并等待一个结果,这个线程就返回到线程池,从而能够执行一些其他的操作。 总而言之,您的应用程序可以用更less的资源完成更多的工作,并且可以提高可伸缩性。

一种方法可能是(我已经在客户应用程序中成功地使用了这个function)使Windows服务运行带有工作线程的冗长操作,然后在IIS中执行以释放线程,直到阻塞操作完成:注意,这个假设结果存储在一个表(由jobId标识的行)和清理过程中,在使用后几个小时清理它们。

为了回答这个问题,“鉴于我的问题和上下文,如何使webAPI操作asynchronous获益? 考虑到这是“相当长的操作”,我想了很多秒,而不是毫秒,这种方法释放IIS线程。 很明显,你还必须运行一个本身占用资源的Windows服务,但是这种方法可以防止大量的慢速查询从系统的其他部分窃取线程。

 // GET api/<controller> [HttpGet] [Route("pharmacies/{pharmacyId}/page/{page}/{filter?}")] public async Task<CartTotalsDTO> GetProductsWithHistory(Guid pharmacyId, int page, string filter = null ,[FromUri] bool refresh = false) { var jobID = Guid.NewGuid().ToString() var job = new Job { Id = jobId, jobType = "GetProductsWithHistory", pharmacyId = pharmacyId, page = page, filter = filter, Created = DateTime.UtcNow, Started = null, Finished = null, User = {{extract user id in the normal way}} }; jobService.CreateJob(job); var timeout = 10*60*1000; //10 minutes Stopwatch sw = new Stopwatch(); sw.Start(); bool responseReceived = false; do { //wait for the windows service to process the job and build the results in the results table if (jobService.GetJob(jobId).Finished == null) { if (sw.ElapsedMilliseconds > timeout ) throw new TimeoutException(); await Task.Delay(2000); } else { responseReceived = true; } } while (responseReceived == false); //this fetches the results from the temporary results table return jobService.GetProductsWithHistory(jobId); }