c# – 用于在库中编写同步和异步方法并使其保持干燥的模式

前端之家收集整理的这篇文章主要介绍了c# – 用于在库中编写同步和异步方法并使其保持干燥的模式前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
参见英文答案 > Using async await when implementing a library with both synchronous and asynchronous API for the same functionality2个
我正在修改库以添加异步方法.从 Should I expose synchronous wrappers for asynchronous methods?开始,它指出我不应该在调用同步方法时在Task.Result周围编写一个包装器.但是,我如何在异步方法和同步方法之间复制大量代码,因为我们希望在库中保留两个选项?

例如,库当前使用TextReader.Read方法.部分异步更改我们想使用TextReader.ReadAsync方法.由于这是库的核心,我似乎需要在同步和异步方法之间复制大量代码(希望尽可能保持代码DRY).或者我需要在PreRead和PostRead方法中重构它们,这似乎使代码混乱,以及TPL试图解决的问题.

我正在考虑将TextReader.Read方法包装在Task.Return()中.即使它是一项任务,TPL的改进也不应该让它切换到不同的线程,我仍然可以使用异步等待大多数代码,就像正常一样.那么同步的包装器可以只是Task.Result还是Wait()呢?

我查看了.net库中的其他示例. StreamReader似乎复制了异步和非异步之间的代码. MemoryStream执行Task.FromResult.

还计划到处都可以添加ConfigureAwait(false),因为它只是一个库.

更新:

我所说的重复代码

public decimal ReadDecimal()
 {
     do
     {
          if (!Read())
          {
               SetInternalProperies()
          }
          else
          {
               return _reader.AsDecimal();
          }
      } while (_reader.hasValue)
 }

 public async Task<decimal> ReadDecimalAsync()
 {
     do
     {
          if (!await ReadAsync())
          {
               SetInternalProperies()
          }
          else
          {
               return _reader.AsDecimal();
          }
      } while (_reader.hasValue)
  }

这是一个小例子,但您可以看到唯一的代码更改是等待和任务.

为了说清楚我想在库中的所有位置使用async / await和TPL进行编码,但我仍然需要使用旧的同步方法.我不仅仅是Task.FromResult()的同步方法.我想的是有一个标志,说我想要同步方法,并在根检查标志的东西

public decimal ReadDecimal()
 { 
     return ReadDecimalAsyncInternal(true).Result;
 }

 public async Task<decimal> ReadDecimal()
 {
     return await ReadDecimalAsyncInternal(false);
 }

 private async Task<decimal> ReadDecimalAsyncInternal(bool syncRequest)
 {
     do
     {
          if (!await ReadAsync(syncRequest))
          {
               SetInternalProperies()
          }
          else
          {
               return _reader.AsDecimal();
          }
      } while (_reader.hasValue)
}

private Task<bool> ReadAsync(bool syncRequest)
{
    if(syncRequest)
    {
        return Task.FromResult(streamReader.Read())
    }
    else
    {
        return StreamReader.ReadAsync(); 
    }
}

解决方法

除了lib中的同步方法之外,您还想添加异步方法.您链接文章正好谈到了这一点.它建议为这两个版本创建专门的代码.

现在通常会给出建议,因为:

>异步方法应该是低延迟.为了提高效率,他们应该在内部使用异步IO.
>出于效率原因,同步方法应在内部使用同步IO.

如果您创建包装器,可能会误导调用者.

现在,如果你对后果感到满意,那么就可以通过两种方式创建包装器.它当然可以节省大量代码.但您必须决定是优先同步还是异步版本.另一个效率较低,没有基于性能的理由存在.

你很少在BCL中找到这个,因为实施的质量很高.但是例如ADO.NET 4.5的sqlConnection类使用sync-over-async.执行sql调用的成本远远高于同步开销.这是一个好的用例. MemoryStream使用(种类)async-over-sync,因为它本质上只是cpu工作,但它必须实现Stream.

实际上是什么开销?期望能够每秒运行> 1亿个Task.FromResult,并且每秒运行数百万个几乎为零的Task.Run.与许多事情相比,这是一个很小的开销.

原文链接:https://www.f2er.com/csharp/100057.html

猜你在找的C#相关文章