我们需要在代码中写一些日志。
日志是通过网络请求编写的,该请求记录了一些信息(记录器是Http-API模块),但是,如果API中存在异常,我们不想破坏整个流程。
我不使用Task.Run
进行这种操作,因为它很糟糕。
但是后来我想到了non-awaitable-inline-function,像这样:
private static readonly HttpClient client = new HttpClient();
void Main()
{
Console.WriteLine(1);
async Task LogMe()
{
var response = await client.PostAsync("http://www.NOTEXISTS.com/recepticle.aspx", null);
var responseString = await response.Content.ReadAsStringAsync();
//response.EnsureSuccessStatusCode(); // I don't need this here
Console.WriteLine("error");
}
//some code
LogMe();
//some code
Console.WriteLine(3);
}
输出:
1
2
问题:
以“一劳永逸”模式登录是否可行?
如果我在此内联方法中创建对象该怎么办?
答案 0 :(得分:5)
我不使用Task.Run进行这种操作,因为它很糟糕。
重要的是要识别/指定此类陈述的上下文。 Task.Run
在ASP.NET上是不正确的。在客户端的GUI应用程序中使用完全可以。
我们需要在代码中写一些日志。
我强烈建议使用已建立的日志库。它们中的大多数通过使用内存队列来工作,该队列由代码(同步)写入,并由后台线程连续处理。这是一个公认的模式。
以“一劳永逸”模式登录是否可行?
“一劳永逸”的问题之一是您不知道何时有错误。建立的日志库都具有某种系统来处理与日志后端通信的错误。您发布的代码只会忽略它们。
如果我在此内联方法中创建对象怎么办,何时将它们进行GC处理?
从概念上讲,只要异步方法将来会继续执行,它们就充当GC的“根”。因此,方法完成后,将对本地对象进行GC处理。
答案 1 :(得分:4)
我不使用Task.Run进行这种操作,因为它很糟糕。
这还不错。这只是工具带中的另一种工具。
理解异步方法如何工作很重要。异步方法都像其他方法一样开始同步运行。魔术发生在作用于不完整await
的第一个Task
上。此时,await
看到不完整的Task
,并且方法 returns 。通常,它返回自己不完整的Task
,除非该方法为async void
,则它什么也不返回。
异步与方法运行无关。关于方法等待。
因此,在您的代码中,LogMe()
将开始在同一线程上运行。只有在等待响应时,Task
才会返回到调用堆栈中,您可以随时等待。
设置请求和发送请求所花费的时间并不多。因此,您不会注意到它。但是,如果您做的事情在请求之前确实做了一些CPU密集型工作,那么使用Task.Run
是适当的,因为这会告诉它在不同的线程上 start ,因此它不会阻止你。
如果这是ASP.NET(不是Core),那么您可能会受益于使用Task.Run
或在.ConfigureAwait(false)
上使用PostAsync
,因为否则它将尝试返回到相同的同步上下文(当前传入HTTP请求的上下文),这意味着当前请求无法在LogMe()
完成之前完成。
但是,如果您要开火而忘记了,那么请记住,无论启动什么操作都不会知道操作是否成功。如果要在其他地方(文本文件或其他内容)记录故障,则应在try
内使用catch
/ LogMe
。如果发送请求时出现问题(DNS查找失败,无响应等),PostAsync
将引发异常。