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

2024-01-02

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

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

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

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(例如旋转器或进度条),也就是说,用户不会感觉到任何延迟。

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

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

EDIT:

我读了这个问题 https://stackoverflow.com/questions/32606485/calling-an-async-method-using-a-task-run-seems-wrong但它不一样。这个问题是关于单身人士的选择await异步方法与单个方法Task.Run等待。这个问题是关于拨打1000的后果await以及由于线程之间不断切换而产生的资源开销。


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

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

Using ConfigureAwait(false)允许您避免 UI 不必要地负责非 UI 工作,同时还可以防止您需要调度线程池线程来完成比它们需要做的更多的工作。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

许多等待异步方法,还是单个等待包装 Task.Run? 的相关文章

  • 静态只读字符串数组

    我在我的 Web 应用程序中使用静态只读字符串数组 基本上数组有错误代码 我将所有类似的错误代码保存在一个数组中并检查该数组 而不是检查不同常量字符串中的每个错误代码 like public static readonly string m
  • 如何从 C# 中的 dataTable.Select( ) 查询中删除单引号?

    所以我有一个经销商名称列表 我正在我的数据表中搜索它们 问题是 一些傻瓜必须被命名为 Young s 这会导致错误 drs dtDealers Select DealerName dealerName 所以我尝试替换字符串 尽管它对我不起作
  • GetType() 在 Type 实例上返回什么?

    我在一些调试过程中遇到了这段代码 private bool HasBaseType Type type out Type baseType Type originalType type GetType baseType GetBaseTyp
  • 在c#中执行Redis控制台命令

    我需要从 Redis 控制台获取 客户端列表 输出以在我的 C 应用程序中使用 有没有办法使用 ConnectionMultiplexer 执行该命令 或者是否有内置方法可以查找该信息 CLIENT LIST是 服务器 命令 而不是 数据库
  • ComboBox DataBinding 导致 ArgumentException

    我的几个类对象 class Person public string Name get set public string Sex get set public int Age get set public override string
  • C++ 是否可以在 MacOS 上与 OpenMP 和 boost 兼容?

    我现在已经尝试了很多事情并得出了一些结论 也许 我监督了一些事情 但似乎我无法完成我想要的事情 问题是 是否有可能使用 OpenMP 和 boost 在 MacOS High Sierra 上编译 C 一些发现 如果我错了请纠正我 Open
  • 如何在C(Linux)中的while循环中准确地睡眠?

    在 C 代码 Linux 操作系统 中 我需要在 while 循环内准确地休眠 比如说 10000 微秒 1000 次 我尝试过usleep nanosleep select pselect和其他一些方法 但没有成功 一旦大约 50 次 它
  • Visual Studio 在构建后显示假错误

    我使用的是 Visual Studio 2017 构建后 sln在调试模式下 我收到错误 但是 当我通过双击错误列表选项卡中的错误来访问错误时 错误会从页面中消失 并且错误数量也会减少 我不太确定这种行为以及为什么会发生这种情况 有超过 2
  • 使用 GCP 的数据存储区时如何区分代码是在模拟器中运行还是在 GKE 中运行

    按照中给出的说明进行操作后 我不确定是否遗漏了任何内容https cloud google com datastore docs tools datastore emulator https cloud google com datasto
  • 告诉 Nancy 将枚举序列化为字符串

    Nancy 默认情况下在生成 JSON 响应时将枚举序列化为整数 我需要将枚举序列化为字符串 有一种方法可以通过创建来自定义 Nancy 的 JSON 序列化JavaScript 原始转换器 https github com NancyFx
  • 为什么可以通过ref参数修改readonly字段?

    考虑 class Foo private readonly string value public Foo Bar ref value private void Bar ref string value value hello world
  • C# 存档中的文件列表

    我正在创建一个 FileFinder 类 您可以在其中进行如下搜索 var fileFinder new FileFinder new string C MyFolder1 C MyFolder2 new string
  • 启动时的 Excel 加载项

    我正在使用 Visual C 创建 Microsoft Excel 的加载项 当我第一次创建解决方案时 它包含一个名为 ThisAddIn Startup 的函数 我在这个函数中添加了以下代码 private void ThisAddIn
  • 如何在 C 中安全地声明 16 位字符串文字?

    我知道已经有一个标准方法 前缀为L wchar t test literal L Test 问题是wchar t不保证是16位 但是对于我的项目 我需要16位wchar t 我还想避免通过的要求 fshort wchar 那么 C 不是 C
  • 为什么我的单选按钮不起作用?

    我正在 Visual C 2005 中开发 MFC 对话框应用程序 我的单选按钮是 m Small m Medium 和 m Large 它们都没有在我的 m Summary 编辑框中显示应有的内容 可能出什么问题了 这是我的代码 Pizz
  • WPF DataGridTemplateColumn 组合框更新所有行

    我有这个 XAML 它从 ItemSource 是枚举的组合框中选择一个值 我使用的教程是 http www c sharpcorner com uploadfile dpatra combobox in datagrid in wpf h
  • OpenGL:仅获取模板缓冲区而没有深度缓冲区?

    我想获取一个模板缓冲区 但如果可能的话 不要承受附加深度缓冲区的开销 因为我不会使用它 我发现的大多数资源表明 虽然模板缓冲区是可选的 例如 排除它以利于获得更高的深度缓冲区精度 但我还没有看到任何请求并成功获取仅 8 位模板缓冲区的代码
  • 可访问性不一致:参数类型的可访问性低于方法

    我试图在两个表单之间传递一个对象 基本上是对当前登录用户的引用 目前 我在登录表单中有一些类似的内容 private ACTInterface oActInterface public void button1 Click object s
  • 如何将十六进制字符串转换为无符号长整型?

    我有以下十六进制值 CString str str T FFF000 如何将其转换为unsigned long 您可以使用strtol作用于常规 C 字符串的函数 它使用指定的基数将字符串转换为 long long l strtol str
  • OpenCV SIFT 描述符关键点半径

    我正在深入研究OpenCV的SIFT描述符提取的实现 https github com Itseez opencv blob master modules nonfree src sift cpp 我发现了一些令人费解的代码来获取兴趣点邻域

随机推荐