在C#中将方法转换为异步的正确方法?
我试图将以下方法(简化示例)转换为异步,因为cacheMissResolver调用在时间方面可能很昂贵(数据库查找,网络调用):
// Synchronous version public class ThingCache { private static readonly object _lockObj; // ... other stuff public Thing Get(string key,Func<Thing> cacheMissResolver) { if (cache.Contains(key)) return cache[key]; Thing item; lock(_lockObj) { if (cache.Contains(key)) return cache[key]; item = cacheMissResolver(); cache.Add(key,item); } return item; } } 关于消费异步方法有很多关于在线的材料,但我在生产它们时发现的建议似乎不那么明确.鉴于这是为了成为图书馆的一部分,我的下列任何一种尝试都是正确的吗? // Asynchronous attempts public class ThingCache { private static readonly SemaphoreSlim _lockObj = new SemaphoreSlim(1); // ... other stuff // attempt #1 public async Task<Thing> Get(string key,Func<Thing> cacheMissResolver) { if (cache.Contains(key)) return await Task.FromResult(cache[key]); Thing item; await _lockObj.WaitAsync(); try { if (cache.Contains(key)) return await Task.FromResult(cache[key]); item = await Task.Run(cacheMissResolver).ConfigureAwait(false); _cache.Add(key,item); } finally { _lockObj.Release(); } return item; } // attempt #2 public async Task<Thing> Get(string key,Func<Task<Thing>> cacheMissResolver) { if (cache.Contains(key)) return await Task.FromResult(cache[key]); Thing item; await _lockObj.WaitAsync(); try { if (cache.Contains(key)) return await Task.FromResult(cache[key]); item = await cacheMissResolver().ConfigureAwait(false); _cache.Add(key,item); } finally { _lockObj.Release(); } return item; } } 使用SemaphoreSlim是否是在异步方法中替换lock语句的正确方法? (我无法在锁定声明的正文中等待.) 我应该使用类型为Func< Task< Thing>>的cacheMissResolver参数代替?虽然这会增加确保解析器func在调用者上是异步的负担(包装在Task.Run中,但我知道如果需要很长时间,它将被卸载到后台线程). 谢谢. 解决方法
是.
是.它将允许调用者提供固有的异步操作(例如IO),而不是使其仅适用于长时间运行CPU绑定工作的工作. (通过简单地让调用者自己使用Task.Run来支持CPU绑定工作,如果这是他们想要做的事情.) 除此之外,请注意等待Task.FromResult(…)没有意义;在Task中包装一个值只是为了立即打开它是没有意义的.只需在这种情况下直接使用结果,在这种情况下,直接返回缓存的值.你正在做的事情并不是真的错,它只是不必要地使代码变得复杂/混乱. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |