在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

查看:195
本文介绍了在C#中执行异步触发时省略await语句并使用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 / 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:


  1. cmd.Dispose()(根据设计或事故)直到 cmd.ExecuteNonQueryAsync 能够完成其工作后才返回-这意味着您实际上仅从 cmd.Dispose cmd.ExecuteNonQueryAsync 之后;在这种情况下,代码可以工作,但是您不能从await / async中受益;

  2. cmd.Dispose()被执行阻止 cmd.ExecuteNonQueryAsync()完成的方式;在这种情况下,代码将无法正常工作;

  1. Either cmd.Dispose() (by design or accident) does not return until cmd.ExecuteNonQueryAsyncwas able to do its work - meaning that you actually only return from cmd.Dispose after cmd.ExecuteNonQueryAsync; in that case, the code works, but you do not benefit from await/async;
  2. Or cmd.Dispose() is executed in a way that prevents cmd.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆