c# - 许多等待异步方法,还是单个等待包装 Task.Run?

标签 c# async-await c#-5.0

假设我们必须通过异步流程在数据库中写入包含 1000 个元素的列表。是等待 1000 次异步插入语句更好,还是将所有 1000 次插入包装在一个封装到 Task.Run 中的单个同步方法中?声明,等待一次?

例如,SqlCommand每个方法都与他的async相结合版本。在本例中,我们有一个插入语句,因此我们可以调用 ExecuteNonQueryExecuteNonQueryAsync .

通常,在异步/等待指南中,我们读到,如果您有可用于某些方法的异步版本,则应该使用它。所以假设我们写:

async Task Save(IEnumerable<Savable> savables)
{
    foreach(var savable in savables)
    {
        //create SqlCommand somehow
        var sqlCmd = CreateSqlCommand(savable);

        //use asynchronous version
        await sqlCmd.ExecuteNonQueryAsync();
    }
}

这段代码很清楚。然而,每次它从await部分出去时,它也会在UI线程上返回,然后在遇到的下一个await中返回到后台线程,依此类推(不是吗?)。这意味着用户可能会看到一些延迟,因为 UI 线程不断被 await 的继续中断。执行下一个foreach循环,在这段时间里,用户界面有点卡住。

我想知道我是否可以更好地编写这样的代码:

async Task Save(IEnumerable<Savable> savables)
{
    await Task.Run(() =>
    {
        foreach(var savable in savables)
        {
            //create SqlCommand somehow
            var sqlCmd = CreateSqlCommand(savable);

            //use synchronous version
            sqlCmd.ExecuteNonQuery();
        }
    });
}

这样,整个foreach在辅助线程上执行,无需在 UI 线程和辅助线程之间不断切换。 这意味着 UI 线程可以在 foreach 的整个持续时间内自由更新 View 。 (例如旋转器或进度条),也就是说,用户不会感觉到任何延迟。

我说得对吗?或者我错过了一些关于“异步一直下来”的事情?

我不是在寻找简单的基于意见的答案,而是在寻找异步/等待准则的解释(以防出现这种情况)以及解决该问题的最佳方法。

编辑:

我已阅读 this question但它不一样。这个问题是关于选择一个单await异步方法与单个方法 Task.Run等待。这个问题是关于调用 1000 await 的后果以及线程间不断切换带来的资源开销。

最佳答案

您的分析基本上是正确的。您似乎高估了这会给 UI 线程带来的负担;要求它做的实际工作相当小,所以它很可能能够保持良好状态,但有可能你已经做了足够多的事情而它却做不到,所以你这样做是对的不想在 UI 线程上执行延续。

当然,您缺少的是避免所有回调 UI 线程的首选方法。当您等待某个操作时,如果您实际上不需要方法的其余部分返回原始上下文,您只需将 ConfigureAwait(false) 添加到末尾即可您正在等待的任务。这将阻止延续在当前上下文(即 UI 线程)中运行,而是让延续在线程池线程中运行。

使用 ConfigureAwait(false) 可以避免 UI 不必要地负责非 UI 工作,同时还可以防止您需要调度线程池线程来完成超出其需要的工作。

当然,如果您在继续之后最终完成的工作实际上是要执行 UI 工作,那么该方法不应该使用 ConfigureAwait(false);,因为它实际上 < em>想要在 UI 线程上安排延续。

关于c# - 许多等待异步方法,还是单个等待包装 Task.Run?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40530737/

相关文章:

c# - 种子实体和用户、角色?

c# - 如何重载函数以接受异步和同步版本的回调参数

entity-framework - 为什么 DbSet<TEntity> 不实现 EnumerableAsync

c# - 将 Excel 文件导出为 PDF - 在尝试关闭 Excel 文件时卡住

c# - 如何反编译/编译dll文件?

javascript - 调用函数数组,每个函数接收一个回调

c# - 执行 client.SendAsync 时出现 HttpRequestException

c# - 如何衡量等待异步操作的性能?

c# - 新的 C# 5.0 'async' 和 'await' 关键字是否使用多核?

c# - System.IO.File 不包含 ReadAllBytes C#