Lazy без кэширования исключенийC#

Место общения программистов C#
Ответить
Anonymous
 Lazy без кэширования исключений

Сообщение Anonymous »

Существует ли System.Lazy без кэширования исключений? Или другое хорошее решение для ленивой многопоточной инициализации и кэширования?

У меня есть следующая программа (поиграйте с ней здесь):

Код: Выделить всё

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 _producedLightsabers;

public LightsabersCache(LightsaberProvider lightsaberProvider)
{
_lightsaberProvider = lightsaberProvider;
_producedLightsabers = new ConcurrentDictionary();
}

public string GetLightsaber(string jedi)
{
Lazy result;
if (!_producedLightsabers.TryGetValue(jedi, out result))
{
result = _producedLightsabers.GetOrAdd(jedi, key => new Lazy(() =>
{
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);
}
});
}
}
}
По сути, я хочу кэшировать изготовленные световые мечи, но их производство дорого и сложно — иногда могут быть исключения. Я хочу разрешить одновременно только одному производителю для данного джедая, но когда выдается исключение, я хочу, чтобы другой продюсер попробовал еще раз. Таким образом, желаемое поведение аналогично System.Lazy с параметром LazyThreadSafetyMode.ExecutionAndPublication, но без кэширования исключений.

В целом, должны быть выполнены следующие технические требования:
  • нам нужен поточно-ориентированный кеш
  • кэш кеш-ключ-значение. Давайте упростим это, и ключ - это тип строки, а значение также является типом строки.
  • производство элемента является дорогостоящим - поэтому производство должно быть запущено одним и только одним потоком для данного ключа. Производство для ключа "a" не блокирует производство для ключа "b"
  • если производство завершилось успешно - мы хотим кэшировать произведенный элемент
  • если во время производства выдается исключение - мы хотим передать исключение вызывающей стороне. Ответственность вызывающего абонента состоит в том, чтобы принять решение о повторной попытке/отказе/регистрации. Исключение не кэшируется — следующий вызов кэша для этого элемента запустит создание элемента.
В моем примере:
  • у нас есть метод LightsabersCache, LightsabersCache.GetLightsaber получает значение для заданного ключа
  • LightsaberProvider — это всего лишь фиктивный поставщик . Это имитирует производственный характер: производство является дорогостоящим (2 секунды), и иногда (в данном случае только в первый раз, для key="2") выдается исключение
  • программа запускает 15 потоков и каждый поток пытается 10 раз получить значение из диапазона . Выдается только одно исключение, поэтому только один раз мы должны увидеть «Произошла темная сторона…». В диапазоне имеется 5 ключей, поэтому на консоли должно быть только 5 сообщений «Создан световой меч». Мы должны увидеть сообщение «LightsaberProvider.GetFor jedi: x» 6 раз, потому что один раз для каждого ключа + один раз для ключа «2».


Подробнее здесь: https://stackoverflow.com/questions/343 ... on-caching
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»