【问题标题】:Async methods with or without ConfigureAwait on NetStandard lib for Net Core用于 Net Core 的 Net Standard 库中带或不带 ConfigureAwait 的异步方法
【发布时间】:2017-08-11 09:38:54
【问题描述】:

我有一个正在执行批量插入的库。
库是在 .NetStandard(1.4) 中制作的 EfCore 扩展,因此它可用于面向 .NetCore(1.0+) 或完整 NetFramework(4.6.1+) 的 ASP.NET Core 项目
其中一个功能是:

public static BulkInsert<T>(this DbContext context, IList<T> entities)
{
    SqlBulkOperation.InsertAsync<T>(context, entities);
}

internal static class SqlBulkOperation
{
    public static void Insert<T>(DbContext context, IList<T> entities)
    {
        ....
        sqlBulkCopy.WriteToServer(reader);
        ....
    }
}

接下来我添加了具有异步支持的相同方法

public static async Task BulkInsertAsync<T>(this DbContext context, IList<T> entities)
{
    await SqlBulkOperation.InsertAsync<T>(context, entities, null, null);
}

internal static class SqlBulkOperation
{
    public static async Task InsertAsync<T>(DbContext context, IList<T> entities)
    {
        ....
        await sqlBulkCopy.WriteToServer(reader);
        ....
    }
}

现在有人建议我更改异步方法,将 ConfigureAwait(false) 添加到内部方法中,并通过删除显式 async 来优化简单的 async em>async 来自公开方法的关键字,如下所示:

public static Task BulkInsertAsync<T>(this DbContext context, IList<T> entities)
{
    return SqlBulkOperation.InsertAsync<T>(context, entities, null, null, true);
}

internal static class SqlBulkOperation
{
    public static async Task InsertAsync<T>(DbContext context, IList<T> entities)
    {
        await sqlBulkCopy.WriteToServerAsync(reader).ConfigureAwait(false);
    }
}

所以问题是:
在这种情况下使用 ConfigureAwait(false) 更好吗?
其次是从公开的方法中删除 async 关键字以用于示例中的场景是否可取?

PS 我已经阅读了一些关于这些问题的博客和几个问题,但还没有得出结论性的答案。 我读到 ASP.NET Core 不再有“上下文”,所以考虑到这里的最佳实践是什么?

【问题讨论】:

  • 这个问题已经被问过100次了,答案总是一样的:在类库中总是使用.ConfigureAwait(false),在WPF/Console/ASP.NET/ASP.NET Core项目中,从不使用它
  • 那么第二个问题,移除 async 呢?
  • @borisdj 只有在需要继续时才使用 await ,否则只需返回任务。换句话说,如果您在调用它之后不需要任务的结果,那么就不需要等待它。只需返回任务即可。
  • BulkInsertAsync 中的异步不是必需的,因此它可以正常工作。也不需要.ConfigureAwait,因为您从InsertAsync 传递任务。如果没有 async 关键字,您可以获得(最小)更好的性能,因为不需要调用异步状态机,也不需要实例化新的任务。
  • @Nkosi 假设我不需要它。出于好奇,在什么一般情况下我需要任务的结果,或者您能否指定一些示例。

标签: asynchronous asp.net-core async-await configureawait


【解决方案1】:

在这种情况下使用 ConfigureAwait(false) 更好吗?

对于库代码,我一般推荐ConfigureAwait(false)The same advice from nearly half a decade ago still applies today。但是,这里有一些缓解因素:

  • 您的只有目标平台不提供SynchronizationContext。因此,只要您的代码仅在这些平台上运行ConfigureAwait(false) 就不是必需的。
  • ASP.NET Core 和EF Core teams no longer use ConfigureAwait(false)。但是,请注意 EF Core 团队确实提供了同步 API,因此人们的想法是首先不会阻塞他们的异步代码,因此缺少ConfigureAwait(false) 不会'在带有SynchronizationContext 的平台上使用时不会导致死锁。

因此,在您的情况下,您可以选择来包含ConfigureAwait(false)。我会说这是一种有效的方法,因为您的库是 EFCore 的扩展,并且您提供同步和异步 API(就像 EFCore 一样)。请记住,这会在用户安装到具有SynchronizationContext 的平台(例如,经典的 ASP.NET)并阻塞您的异步代码的情况下打开死锁。但 EFCore 也有同样的限制。

顺便说一句,试试the boolean argument hack to prevent code duplication in your synchronous/asynchronous method pairs

其次是从公开的方法中删除 async 关键字以用于示例中的场景是否明智?

没有。我不确定为什么会推荐这个。它可以防止最终用户检测到您是否在使用 async 关键字(编译器在 async 方法上放置了一个属性),但谁在乎呢?

【讨论】:

  • 我的理解是不需要异步,因为只有一个调用并且没有 using 也没有 try 块,而好处是性能稍好。
  • @borisdj:如果你只是调用另一个方法,那么是的,eliding async is fine。您问题中的示例代码看起来像是专门添加了一个仅限内部的 async 方法,以便实际的 API 上不会有 async,这只会 add 开销。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-26
  • 1970-01-01
  • 2020-03-20
  • 1970-01-01
相关资源
最近更新 更多