我想在C#中执行异步数据库查询,该查询调用备份的存储过程。由于我们使用Azure,因此大约需要2分钟,我们不希望用户等待那么久。
因此,我们的想法是使其异步,以便在请求之后继续运行任务。
[HttpPost]
public ActionResult Create(Snapshot snapshot)
{
db.Database.CommandTimeout = 7200;
Task.Run(() => db.Database.ExecuteSqlCommandAsync("EXEC PerformSnapshot @User = '" + CurrentUser.AccountName + "', @Comment = '" + snapshot.Comment + "';"));
this.ShowUserMessage("Your snapshot has been created.");
return this.RedirectToActionImpl("Index", "Snapshots", new System.Web.Routing.RouteValueDictionary());
}
我担心我不理解异步设备的概念。如果我不使用wait语句,查询将不会被执行(或中止?)。但实际上“等待”是我特别想做的一件事。
所以...为什么我被迫在这里等待?
或者该方法是否会启动,但如果请求完成则会被杀死?
答案 0 :(得分:1)
我们不希望用户等那么久。
async-await
无法帮助您。听起来很奇怪,基本async-await
模式是关于以非阻塞方式实现同步行为 。它没有重新安排你的逻辑流程;事实上,它需要付出很大的努力来保护它。你在这里进行async改变的唯一一点是你在2分钟的数据库操作期间不再占用一个线程,如果你有很多并发用户,这是一个巨大的赢得你的应用程序的可扩展性,但是没有加快个人请求。
我认为您真正想要的是将操作作为后台作业运行,以便您可以立即响应用户。但是要小心 - 在ASP.NET中有bad ways这样做(即Task.Run
)并且有good ways。
答案 1 :(得分:0)
假设您有足够数量的线程能够处理HTTP请求。此异步代码将帮助您在每个时间段处理更多请求,但它无法帮助用户更快地完成工作。
答案 2 :(得分:0)
这似乎归结为对async
和await
做什么的误解。
async
并不意味着run this on a new thread
,实质上它是编译器构建状态机的信号,所以这样的方法:
Task<int> GetMeAnInt()
{
return await myWebService.GetMeAnInt();
}
有点(不能强调这一点),变成了这个:
Task<int> GetMeAnInt()
{
var awaiter = myWebService.GetMeAnInt().GetAwaiter();
awaiter.OnCompletion(() => goto done);
return Task.InProgress;
done:
return awaiter.Result;
}
MSDN has way more information关于此问题,甚至还有一些代码解释了如何建立自己的等待者。
async
和await
只是让你能够编写使用回调的代码,但是以一种很好的方式告诉编译器为你做繁重的工作。
如果你真的想在后台运行某些东西,那么你需要使用Task
:
Task<int> GetMeAnInt()
{
return Task.Run(() => myWebService.GetMeAnInt());
}
OR
Task<int> GetMeAnInt()
{
return Task.Run(async () => await myWebService.GetMeAnInt());
}
第二个示例在lambda中使用async和await,因为在此方案中,Web服务上的GetMeAnInt
也恰好返回Task<int>
。
回顾一下:
async
和await
只是指示编译器执行一些jiggerypokery
goto
async
并不意味着&#34;在后台线程上运行&#34; Task.Run()
可用于对线程池线程进行排队以运行任意函数Task.Factory.Start()
可用于获取一个全新的线程来运行任意函数await
指示编译器这是awaiter
awaitable
的结果(例如任务)为awaited
的点 - 这就是它知道如何构建状态机。答案 3 :(得分:0)
正如我在MSDN article on async
ASP.NET中描述的那样,async
不是银弹;它不会改变HTTP协议:
当一些开发人员了解异步并等待时,他们认为这是服务器代码“屈服”到客户端(例如,浏览器)的一种方式。但是,async和等待ASP.NET只能“屈服”到ASP.NET运行时; HTTP协议保持不变,每个请求仍然只有一个响应。
在您的情况下,您尝试使用Web请求启动后端操作,然后返回浏览器。 ASP.NET不是为了执行像这样的后端操作而设计的。它只是一个Web层框架。让ASP.NET执行工作很危险,因为ASP.NET只知道来自其请求的工作。
我的博客上有overview of various solutions。请注意,使用普通Task.Run
,Task.Factory.StartNew
或ThreadPool.QueueUserWorkItem
非常危险,因为ASP.NET对此工作一无所知。在至少,你应该使用HostingEnvironment.QueueBackgroundWorkItem
,所以ASP.NET至少知道这项工作。但这并不能保证工作真的能够完成。
正确的解决方案是将工作放在一个持久队列中,并拥有一个独立的后台工作进程队列。请参阅Asynchronous Messaging Primer(具体而言,您的方案是“解耦工作负载”)。