我是C#的新手,并试图了解如何使用Lazy
.
我需要通过等待已经运行的操作的结果来处理并发请求.对数据的请求可以与相同/不同的凭证同时进行.
对于每个唯一的凭证集,最多可以有一个GetDataInternal调用正在进行中,其中一个调用的结果在准备就绪时返回给所有排队的服务员
private readonly ConcurrentDictionary> Cache = new ConcurrentDictionary >(); public Data GetData(Credential credential) { // This instance will be thrown away if a cached // value with our "credential" key already exists. Lazy newLazy = new Lazy( () => GetDataInternal(credential), LazyThreadSafetyMode.ExecutionAndPublication ); Lazy lazy = Cache.GetOrAdd(credential, newLazy); bool added = ReferenceEquals(newLazy, lazy); // If true, we won the race. Data data; try { // Wait for the GetDataInternal call to complete. data = lazy.Value; } finally { // Only the thread which created the cache value // is allowed to remove it, to prevent races. if (added) { Cache.TryRemove(credential, out lazy); } } return data; }
这是正确的使用方式Lazy
还是我的代码不安全?
更新:
开始使用MemoryCache
而不是ConcurrentDictionary
?如果是,那么如何创建一个键值,因为它是一个string
内部MemoryCache.Default.AddOrGetExisting()
这是对的.这是一个标准模式(删除除外),它是一个非常好的缓存,因为它可以防止缓存加盖.
我不确定你想在计算完成后从缓存中删除,因为计算将一遍又一遍地重做.如果您不需要删除,则可以通过基本删除后半部分来简化代码.
注意,Lazy
在异常情况下存在问题:存储异常并且永远不会重新执行工厂.问题永远存在(直到人重新启动应用程序).在我看来,这Lazy
在大多数情况下完全不适合生产使用.
这意味着诸如网络问题之类的瞬态错误可能会导致应用永久不可用.