Nom*_*mad 7 c# asynchronous task async-await asp.net-core
我正在尝试实现一个简单的日志库,它将用于多个项目.库的工作是将HTTP请求发送到ElasticSearch.这个库的要点是它不能等待响应.另外,我不关心任何错误/异常.它必须将请求发送到ElasticSearch,并立即返回.我不想用返回类型创建接口Task,我希望它们留下来void.
以下是我的示例代码.这是"火与忘"的正确和安全的实施吗?如果我Task.Run()在高负载库中使用它可以吗?或者我应该避免Task.Run()在我的情况下使用?另外,如果我不使用await带Task.Run(),将我阻塞线程?此代码在库中:
public enum LogLevel
{
Trace = 1,
Debug = 2,
Info = 3,
Warn = 4,
Error = 5,
Fatal = 6
}
public interface ILogger
{
void Info(string action, string message);
}
public class Logger : ILogger
{
private static readonly HttpClient _httpClient = new HttpClient(new HttpClientHandler { Proxy = null, UseProxy = false });
private static IConfigurationRoot _configuration;
public Logger(IConfigurationRoot configuration)
{
_configuration = configuration;
}
public void Info(string action, string message)
{
Task.Run(() => Post(action, message, LogLevel.Info));
/*Post(action, message, LogLevel.Info);*/ // Or should I just use it like this?
}
private async Task Post(string action, string message, LogLevel logLevel)
{
// Here I have some logic
var jsonData = JsonConvert.SerializeObject(log);
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(_configuration.GetValue<string>("ElasticLogger:Url"), content);
// No work here, the end of the method
}
}
Run Code Online (Sandbox Code Playgroud)
这是我在web api的Startup类中的ConfigureServices方法中注册logger的方法:
public void ConfigureServices(IServiceCollection services)
{
// ......
services.AddSingleton<ILogger, Logger>();
// .....
}
Run Code Online (Sandbox Code Playgroud)
这段代码在我的web api中的方法中:
public void ExecuteOperation(ExecOperationRequest request)
{
// Here some business logic
_logger.Info("ExecuteOperation", "START"); // Log
// Here also some business logic
_logger.Info("ExecuteOperation", "END"); // Log
}
Run Code Online (Sandbox Code Playgroud)
Re: 未等待调用异步方法 vs Task.Run()
由于只有少量 CPU 绑定工作Post(即创建 json 有效负载),因此没有其他好处Task.Run- 在线程池上调度新任务的开销将超过 IMO 的任何好处。IE
Post(action, message, LogLevel.Info);*/ // Or should I just use it like this?
Run Code Online (Sandbox Code Playgroud)
是两种方法中较好的一种。您可能希望取消与未等待任务相关联的编译器警告,并为下一个遇到代码的开发人员留下评论。
但是根据 Stephen Cleary 的明确回答,在ASP.Net 中即发即弃几乎从来都不是一个好主意。最好是将工作(例如通过队列)卸载到 Windows 服务、Azure Web 作业等。
还有其他危险 - 如果未等待的 Task 抛出,您将需要观察异常。
另外,请注意,在Post(例如,如果您使用response)之后完成的任何工作,这仍然是一个需要在线程池上安排的延续任务 - 如果您启动大量Post方法,您会得到很多当它们完成时线程争用。
Re: 另外,如果我不将await 与Task.Run() 一起使用,我会阻塞线程吗?
await 不需要线程。await是要求编译器异步重写代码的语法糖。
Task.Run()将在 ThreadPool 上安排第二个任务,该任务在命中该PostAsync方法之前只会做很少的工作,这就是为什么建议不要使用它的原因。
来自Infoto的未等待调用的调用者线程使用量/阻塞量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
}
Run Code Online (Sandbox Code Playgroud)
回复:异常处理
try..catch块与异步代码一起工作 -await将检查故障Task并引发异常:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
虽然以上都符合观察异常的标准,但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;
});
};
Run Code Online (Sandbox Code Playgroud)
注意,上面的处理程序只有在 GC 收集 Task 时才会触发,这可能是在发生异常之后的一段时间。
| 归档时间: |
|
| 查看次数: |
2299 次 |
| 最近记录: |