[英]Debugging async await controller action
我在ApiController中隐含了(我认为是)一个简单的异步方法,如下所示:
public class CommentsController : ApiController
{
private static readonly IList<CommentModel> Comments;
static CommentsController()
{
// Note: Removed to abbreviate - populate comments manually here.
}
[ResponseType(typeof (IList<CommentModel>))]
[HttpGet]
public async Task<IHttpActionResult> GetAllComments()
{
return await Task.Factory.StartNew(() =>
{
Thread.Sleep(10000); // Breakpoint #1
return Ok(Comments); // Breakpoint #2
});
// Breakpoint #3
}
}
注意我在上面放置的断点。
我期望发生的事情是在我单击“继续”时在#1处等待线程等待,但流程在此阶段继续通过#3。
然后,当睡眠结束后,再次继续并在#2处休息。
但是,在调试过程中,它似乎是同步的。
我的问题是,首先,这是真正的异步吗?如何调试它以进行验证,或者进行单元测试?
但是,在调试过程中,它似乎是同步的。
它是串行的(不是同步的),因为await
关键字告诉该方法在该操作完成之前不要继续。 调试器将以串行方式逐步执行异步方法,这可以使它们显得同步。 这比让调试器跳到不相关的代码然后再跳回去要自然得多。
我的问题首先是这种真正的异步
它是假的异步的。 在实际代码中,您永远不会使用Task.Factory.StarNew
。
此外,对于ASP.NET应用程序,应避免将工作发送到线程池( StartNew
, Task.Run
等)。 相反,您应该调用自然异步API。
如何调试它以进行验证,或者进行单元测试?
您可以调用该方法,确认任务尚未完成,然后等待它。 请注意,为避免出现竞争情况,您应该对控制器正在使用的任何异步服务进行存根。
断点3将永远不会被击中,应该不会。
以Task.Factory.StartNew
开头的Task
将异步运行。
但是await
基本上是等待Task
完成执行,然后再继续当前方法,然后将执行返回给调用方。 因此,它为给定Task
添加了延续 。
由于您要返回Task
的结果,因此断点3将永远不会执行。
如果希望Breakpoint 3在Task
之后执行,则基本上有2个选项:
您可以添加延续:
return await Task.Factory.StartNew(() =>
{
Thread.Sleep(10000); // Breakpoint #1
return Ok(Comments); // Breakpoint #2
}).ContinueWith((Task<IHttpActionResult> t) =>
{
//t.Result contains the result of the previous Task
return t.Result; // Breakpoint #3
});
或者(更简单),使用一个临时值并await
:
var temp = await Task.Factory.StartNew(() =>
{
Thread.Sleep(10000); // Breakpoint #1
return Ok(Comments); // Breakpoint #2
});
// Breakpoint #3
return temp;
要在不等待执行完成的情况下调用async
方法,只需忽略await
。 因此,如果您想并行执行5次GetAllComments
,可以这样做:
for(int i = 0; i < 5; i++)
GetAllComments();
断点3怎么会被击中? 您在等待之前得到了回报。
因此,将发生的情况是,等待将生成状态机,并且在线程完成时将仅返回该值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.