【问题标题】:Should I actually use async-await in inner methods?我真的应该在内部方法中使用 async-await 吗?
【发布时间】:2020-04-06 19:25:38
【问题描述】:

假设我有以下 3 种方法:

public async Task<int> CalculateData(int index, int trustLevel, string type)
{
    var x = await CalculateBaseScore(index, type);
    return ComplexProcess(x, trustLevel);
}

public async Task<int> CalculateBaseScore(int index, string type)
{
    var conn_string = "...";
    var sql = "...";
    var param = new { Index = index, Type = type };
    using (var conn = new SqlConnection(conn_string))
    {
        var db_output = await conn.ExecuteScalarAsync<int>(sql, param: param);
        return db_output;
    }
}

public int CalculateBaseScore(int index, int trustLevel)
{
    //Omitted
}

如您所见,其中 2 个使用 async-await。

在 Stephen Cleary 的 introduction to async-await 中,据说

如果你可以在没有 await 的情况下编写它,那么你应该在没有 await 的情况下编写它,并从方法中删除 async 关键字。返回 Task.FromResult 的非异步方法比返回值的异步方法更有效。

在这种情况下,Dapper 制造的数据库调用是否符合我可以在不使用 async-await 的情况下编写并简单地返回 Task&lt;int&gt; 对象的方法?如果我改成这个,我会在性能或其他方面获得什么好处吗?

public async Task<int> CalculateData(int index, int trustLevel, string type)
{
    var x = await CalculateBaseScore(index, type);
    return ComplexProcess(x, trustLevel);
}

public Task<int> CalculateBaseScore(int index, string type)
{
    var conn_string = "...";
    var sql = "...";
    var param = new { Index = index, Type = type };
    using (var conn = new SqlConnection(conn_string))
    {
        var db_output_task = conn.ExecuteScalarAsync<int>(sql, param: param);
        return db_output_task;
    }
}

public int CalculateBaseScore(int index, int trustLevel)
{
    //Omitted
}

参见第二个示例,我省略了 CalculateBaseScore 上的 async-await 关键字,只返回了 Task 对象。

【问题讨论】:

  • 这是helpful link。查找标题“删除 async/await 关键字”。答案是肯定的,您可以省略 async 并像在 Dapper 示例中一样返回任务。
  • 只有通过做 X 和不做 X,并比较一个以用户为中心、仔细衡量的性能指标,才能明确回答“如果我做 X,我会获得性能上的胜利”这个问题。唯一能做到这一点的人就是你;如果您有两匹马,并且想知道哪匹马跑得更快,请在互联网上让从未见过您的马匹的陌生人猜一猜并不能代替简单的赛马!
  • @TomTom:我们没有创造价值任务,因为它们更快。我们创建它们是因为它们在任务可能已经完成的情况下降低了收集压力。
  • 另外,正如 Theodor 的回答所指出的,“这些选择中哪一个更快?”要求被比较的两个工作流程都正确并且做同样的事情。首先集中精力!
  • 这几年我改变了我的立场,现在我recommend against eliding async/await 除了在最微不足道的情况下。我现在将更新旧帖子。

标签: c# async-await dapper


【解决方案1】:

关于没有 async-await 的第二个实现:

public Task<int> CalculateBaseScore(int index, string type)
{
    var conn_string = "...";
    var sql = "...";
    var param = new { Index = index, Type = type };
    using (var conn = new SqlConnection(conn_string))
    {
        var db_output_task = conn.ExecuteScalarAsync<int>(sql, param: param);
        return db_output_task;
    }
}

...每次调用将使您的性能提升大约 1 微秒。换句话说,它会在调用它 1,000,000 次后为您节省一秒钟的 CPU 时间。这些是好消息。

坏消息是,所有这 1,000,000 次调用都将导致ObjectDisposedException,因为SqlConnection 将在Task 创建后立即被过早处理。

值得吗?我会说不。从长远来看,保持简单将为您节省更多时间。

【讨论】:

  • 好点;永远记住,工作流必须在工作流中的位置有一个await,在该位置,工作流的其余部分在前一部分完成之前不得继续。如果要求工作流结束时的清理代码在工作流开始完成之前执行,则需要await
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
  • 2018-09-14
  • 1970-01-01
  • 2021-02-07
  • 1970-01-01
  • 2020-06-01
  • 2020-10-09
相关资源
最近更新 更多