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. 如果您创建包装器,可能会误导调用者. 现在,如果你对后果感到满意,那么就可以通过两种方式创建包装器.它当然可以节省大量代码.但您必须决定是优先同步还是异步版本.另一个效率较低,没有基于性能的理由存在. 你很少在BCL中找到这个,因为实施的质量很高.但是例如ADO.NET 4.5的SqlConnection类使用sync-over-async.执行SQL调用的成本远远高于同步开销.这是一个好的用例. MemoryStream使用(种类)async-over-sync,因为它本质上只是CPU工作,但它必须实现Stream. 实际上是什么开销?期望能够每秒运行> 1亿个Task.FromResult,并且每秒运行数百万个几乎为零的Task.Run.与许多事情相比,这是一个很小的开销. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |