在C#中执行异步触发时省略await语句并使用ado.net忘记写入数据库是否安全? [英] Is it safe in C# to omit await statement when doing an async fire and forget write to a database with ado.net
问题描述
在asp.net应用程序中,我想尽可能高效地登录到数据库。我正在使用基本的ADO.NET来写入日志数据库,并且我想异步执行此操作,所以这是我要做的事情:
In an asp.net application I want to log to a database as efficiently as possible. I am using basic ADO.NET to write to the logging database and I want to do this async, so here is what I do:
using (var conn = new SqlConnection(_connectionString)) {
using (var cmd = new SqlCommand("INSERT INTO dbo.Logs (TimeStamp,ThreadId,Level,Message,Exception) VALUES (@TimeStamp,@ThreadId,@Level,@Message,@Exception)", conn)) {
cmd.Parameters.AddWithValue("@TimeStamp", DateTime.UtcNow);
cmd.Parameters.AddWithValue("@ThreadId", Thread.CurrentThread.ManagedThreadId);
cmd.Parameters.AddWithValue("@Level", level);
cmd.Parameters.AddWithValue("@Message", msg);
cmd.Parameters.AddWithValue("@Exception", ex == null ? "" : ex.ToString());
conn.Open();
cmd.ExecuteNonQueryAsync();
}
}
现在我的问题是我是否应该等待cmd.ExecuteNonQueryAsync()语句,或者如果可以省略await也是可以的,因为我基本上只需要执行即弃操作即可。
Now my question is if I should do an await on the cmd.ExecuteNonQueryAsync() statement or if it is ok to omit the await because I basically just need to do a fire-and-forget.
推荐答案
仅触发并忘记异步操作是不正确的-它可能会因异常而失败,并且您几乎肯定会在这种情况下要做一些事情(通知用户/重试/炸毁)。 (此外,如果有人使用特定的选项,则任务中的异常最终将导致进程中断。)
It is not OK to just fire and forget the async operation - it might fail with an exception, and you nearly certainly want to do something (notify the user/retry/blow up) in that case. (Besides, if someone uses a specific option, an exception in the task will eventually bring down the process).
另外:谁负责关闭连接?
Also: Who is responsible for closing the connection?
编辑:为了更清楚地说明连接关闭的问题,我将使用 try $重写using语句c $ c> /
finally
(我知道这不是完全相同的IL,但是它足够接近以查看问题出在哪里)-在这种情况下,代码大致变为:
Edit: In order to make the problem of connection closing clearer, I will rewrite the using statements with try
/finally
(I know it is not the exact same IL, but it is close enough to see where the problem is) - in that case, the code roughly becomes:
SqlConnection conn;
try {
conn = new SqlConnection("connString");
SqlCommand cmd;
try {
cmd = new SqlCommand("INSERT INTO dbo.Logs (TimeStamp,ThreadId,Level,Message,Exception) VALUES (@TimeStamp,@ThreadId,@Level,@Message,@Exception)", conn);
cmd.AddParameters();
conn.Open();
cmd.ExecuteNonQueryAsync();
} finally {
if (cmd != null) cmd.Dispose();
} finally {
if (conn != null) conn.Close();
}
您可以看到 cmd.Dispose()
在 cmd.ExecuteNonQueryAsync()
之后被调用。那怎么行?我看到两种可能性:
You can see that cmd.Dispose()
is called right after cmd.ExecuteNonQueryAsync()
. How can that work? I see two possibilities:
-
cmd.Dispose()
(根据设计或事故)直到cmd.ExecuteNonQueryAsync
能够完成其工作后才返回-这意味着您实际上仅从cmd.Dispose $ c $返回c>在
cmd.ExecuteNonQueryAsync
之后;在这种情况下,代码可以工作,但是您不能从await / async中受益; - 或
cmd.Dispose()
被执行阻止cmd.ExecuteNonQueryAsync()
完成的方式;在这种情况下,代码将无法正常工作;
- Either
cmd.Dispose()
(by design or accident) does not return untilcmd.ExecuteNonQueryAsync
was able to do its work - meaning that you actually only return fromcmd.Dispose
aftercmd.ExecuteNonQueryAsync
; in that case, the code works, but you do not benefit from await/async; - Or
cmd.Dispose()
is executed in a way that preventscmd.ExecuteNonQueryAsync()
from completing; in that case the code does not work;
在两种情况下,程序都是错误的-您需要等待
或对任务调用 Wait()
以确保其行为正确。
In both cases, the program is wrong - you need either await
or to call Wait()
on the task in order to ensure that it behaves correctly.
这篇关于在C#中执行异步触发时省略await语句并使用ado.net忘记写入数据库是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!