c# – 懒惰,无异常缓存
是否有System.Lazy< T>无一例外地缓存?或者懒惰多线程初始化的另一个很好的解决方案&缓存?
我有以下程序(fiddle it here): using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; using System.Net; namespace ConsoleApplication3 { public class Program { public class LightsaberProvider { private static int _firstTime = 1; public LightsaberProvider() { Console.WriteLine("LightsaberProvider ctor"); } public string GetFor(string jedi) { Console.WriteLine("LightsaberProvider.GetFor jedi: {0}",jedi); Thread.Sleep(TimeSpan.FromSeconds(1)); if (jedi == "2" && 1 == Interlocked.Exchange(ref _firstTime,0)) { throw new Exception("Dark side happened..."); } Thread.Sleep(TimeSpan.FromSeconds(1)); return string.Format("Lightsaver for: {0}",jedi); } } public class LightsabersCache { private readonly LightsaberProvider _lightsaberProvider; private readonly ConcurrentDictionary<string,Lazy<string>> _producedLightsabers; public LightsabersCache(LightsaberProvider lightsaberProvider) { _lightsaberProvider = lightsaberProvider; _producedLightsabers = new ConcurrentDictionary<string,Lazy<string>>(); } public string GetLightsaber(string jedi) { Lazy<string> result; if (!_producedLightsabers.TryGetValue(jedi,out result)) { result = _producedLightsabers.GetOrAdd(jedi,key => new Lazy<string>(() => { Console.WriteLine("Lazy Enter"); var light = _lightsaberProvider.GetFor(jedi); Console.WriteLine("Lightsaber produced"); return light; },LazyThreadSafetyMode.ExecutionAndPublication)); } return result.Value; } } public void Main() { Test(); Console.WriteLine("Maximum 1 'Dark side happened...' strings on the console there should be. No more,no less."); Console.WriteLine("Maximum 5 lightsabers produced should be. No more,no less."); } private static void Test() { var cache = new LightsabersCache(new LightsaberProvider()); Parallel.For(0,15,t => { for (int i = 0; i < 10; i++) { try { var result = cache.GetLightsaber((t % 5).ToString()); } catch (Exception e) { Console.WriteLine(e.Message); } Thread.Sleep(25); } }); } } } 基本上我想缓存生产的光剑,但生产它们既昂贵又棘手 – 有时会出现例外情况.我想在给定的jedi时只允许一个生产者,但是当抛出异常时 – 我希望另一个生产者再试一次.因此,期望的行为类似于System.Lazy< T>.使用LazyThreadSafetyMode.ExecutionAndPublication选项,但没有例外缓存. 总而言之,必须满足以下技术要求: >我们想要一个线程安全的缓存 在我的例子中: >我们有LightsabersCache,LightsabersCache.GetLightsaber方法获取给定键的值 解决方法
这很难用
built-in Lazy:你应该将你的
LazyWithoutExceptionCaching.Value吸气剂包裹起来.但这使得内置Lazy的使用变得多余:你将在Lazy.Value getter中拥有不必要的锁.
最好自己编写自己的Lazy实现 public class SimpleLazy<T> where T : class { private readonly Func<T> valueFactory; private T instance; private readonly object locker = new object(); public SimpleLazy(Func<T> valueFactory) { this.valueFactory = valueFactory; this.instance = null; } public T Value { get { lock (locker) return instance ?? (instance = valueFactory()); } } } 附:也许我们将在this issue关闭时内置此功能. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |