当我向它发出请求时,此代码会挂起(不会返回响应):
public class MyController : ApiController
{
public async Task<IQueryable<int>> Get()
{
return await new Task<IQueryable<int>>(() => new List<int>().AsQueryable());
}
}
但这种方法很好用:
public IQueryable<int> Get()
{
return new List<int>().AsQueryable();
}
我错过了什么基础知识?!
答案 0 :(得分:6)
正如另一个答案所指出的,控制器未完成的原因是因为任务未启动。但是,使用Task.Start
,Task.Factory.StartNew
或Task.Run
并不是ASP.NET的好方法。
在ASP.NET上使用async
/ await
的全部意义是释放一个帖子。但是,如果您await
通过Start
/ StartNew
/ Run
启动了一项任务,那么您可以通过占用另一个线程来释放一个线程来自同一线程池的线程。在这种情况下,您不仅会失去async
/ await
的所有好处,而且通过定期抛弃ASP.NET线程池启发式实际上降低您的可伸缩性。< / p>
正如我在我的博客中描述的那样two types of tasks:代表任务(代表在线程上执行的一些工作)和Promise Tasks(代表一个事件)。您应该避免在ASP.NET上委派任务,包括任何已启动的任务&#34; (Start
/ StartNew
/ Run
)。
由于您正在返回IQueryable<T>
,我假设您的实际基础操作是数据库查询。如果您正在使用EF6,那么您完全支持使用Promise Tasks正确实施的asynchronous queries。
答案 1 :(得分:3)
你实际上并没有开始Task
所以它会等待永远不会开始的事情。
而是使用Task.Factory.StartNew
来创建并同时启动,或者调用Task#Start
并等待该调用。
开始任务的方法概述:http://dotnetcodr.com/2014/01/01/5-ways-to-start-a-task-in-net-c/
答案 2 :(得分:0)
在async
/ await
中完全没有必要,该方法可能如下所示:
public Task<IQueryable<int>> Get()
{
return Task.FromResult(new List<int>().AsQueryable());
}
如果你确实需要它async
,那么你总是可以这样写:
public async Task<IQueryable<int>> Get()
{
return await Task.FromResult(new List<int>().AsQueryable());
}
这将引入很少的开销(整个状态机将由编译器生成)。
另外,正如其他人已经说过的那样,从async
方法返回的任务应热(已启动)
请注意,Task.FromResult
将返回已完成的任务,此案例可以通过async/await
生成的代码进行优化,在这种情况下编写Task.Run
至少是非常奇怪的
阅读Task-based Asynchronous Pattern了解更多详情