回复:对异步方法的意外调用与 Task.Run()
由于只有少量 CPU 密集型工作Post
(即创建 json 有效负载),另一个没有任何好处Task.Run
- 在我看来,在线程池上调度新任务的开销将超过任何好处。 IE。
Post(action, message, LogLevel.Info);*/ // Or should I just use it like this?
是两种方法中较好的一种。您可能希望抑制与未等待的任务相关的编译器警告,并为下一个遇到代码的开发人员留下评论。
但根据斯蒂芬·克利里的明确回答,开火后忘记ASP.Net 几乎从来都不是一个好主意 https://stackoverflow.com/q/36335345。最好是卸载工作,例如通过队列、Windows 服务、Azure Web 作业等。
还有额外的危险 - 如果未等待的任务抛出,你会想要观察异常 https://stackoverflow.com/q/3284137/314291.
另请注意,此后完成的任何工作Post
(例如,如果您与response
)这仍然是一个需要在线程池上安排的延续任务 - 如果您触发大量线程Post
方法,当它们完成时你会遇到很多线程争用。
Re : 另外,如果我不将await 与Task.Run() 一起使用,我会阻塞线程吗?
await
不需要线程 https://blog.stephencleary.com/2013/11/there-is-no-thread.html. await
是要求编译器异步重写代码的语法糖。Task.Run()
将在线程池上安排第二个任务,该任务在到达线程池之前只会执行少量工作PostAsync
方法,这就是为什么建议不使用它的原因。
来自未等待的调用的调用者线程使用量/阻塞量Info
to Post
取决于之前完成了什么样的工作Task
被返回。
在您的情况下,Json 序列化工作将在调用者的线程上完成(我已标记为#1),但是与 HTTP 调用持续时间相比,执行时间应该可以忽略不计。所以虽然方法没有等待Info
,HTTP 调用之后的任何代码仍然需要在 Http 调用完成时进行调度,并将调度到任何可用线程上 (#2)。
public void Info(string action, string message)
{
#pragma warning disable 4014 // Deliberate fire and forget
Post(action, message, LogLevel.Info); // Unawaited Task, thread #1
#pragma warning restore 4014
}
private async Task Post(string action, string message, LogLevel logLevel)
{
var jsonData = JsonConvert.SerializeObject(log); // #1
var content = new StringContent(jsonData, Encoding.UTF8, "application/json"); // #1
var response = await httpClient.PostAsync(...), content);
// Work here will be scheduled on any available Thread, after PostAsync completes #2
}
回复:异常处理
try..catch
块与异步代码一起使用 -await
will 检查是否有故障Task https://stackoverflow.com/q/5383310/314291并引发异常:
public async Task Post()
{
try
{
// ... other serialization code here ...
await HttpPostAsync();
}
catch (Exception ex)
{
// Do you have a logger of last resort?
Trace.WriteLine(ex.Message);
}
}
尽管上述内容符合观察异常的标准,但注册一个例外仍然是一个好主意UnobservedTaskException
全局级别的处理程序。
这将帮助您检测并识别未能观察到异常的位置:
TaskScheduler.UnobservedTaskException += (sender, eventArgs) =>
{
eventArgs.SetObserved();
((AggregateException)eventArgs.Exception).Handle(ex =>
{
// Arriving here is BAD - means we've forgotten an exception handler around await
// Or haven't checked for `.IsFaulted` on `.ContinueWith`
Trace.WriteLine($"Unobserved Exception {ex.Message}");
return true;
});
};
请注意,上述处理程序仅在任务被 GC 收集时才会触发,这可能是在异常发生后的一段时间。