Потокобезопасный кешированный объект для запроса asp - PullRequest
0 голосов
/ 25 января 2019

Прежде всего, я не смог сделать название более объяснительным, я постараюсь изложить проблему, а затем предоставлю свое решение для нее

Я реализую бэкэнд в ядре asp для нашей игры,у нас есть несколько запросов, которые несколько велики, как, например, запрос товаров, которые мы предоставляем в магазине, каждый пользователь запускает игру, загружает информацию о магазине, которая совершает поездку по базе данных, чтобы получить всю информацию о магазине, которая, как правило, изменяется - не чаще одного раза в месяц.поэтому мы совершаем тысячи поездок в базу данных, которые не нужны.

Кроме того, мы возвращаем метки времени, когда в последний раз изображение элемента менялось, изображения сохраняются в BLOB-объекте, что заставляет менязапросить в блобе дату изменения, что делает запрос более дорогим

, поэтому для решения всего этого я реализовал небольшой класс для кэширования запроса до тех пор, пока нам не потребуется его обновить, для этого запроса и некоторых других, ноЯ не уверен, правильно ли я смотрю на это

вот базовый абстрактный класс:

public abstract class CachedModel<T>
{
    protected T Model { get; set; }

    private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1,1);

    protected abstract Task ThreadSafeUpdateAsync();
    protected abstract bool NeedsUpdate();

    public async Task<T> GetModel()
    {
        if (NeedsUpdate())
        {
            try
            {
                await semaphore.WaitAsync();
                if(NeedsUpdate()) // not sure if this is needed, can other threads enter here after the first one already updated the object?
                    await ThreadSafeUpdateAsync();
            }
            finally
            {
                semaphore.Release();
            }
        }
        return Model;
    }
}

и тогда яДополнить этот класс для каждого запроса следующим образом:

public class CachedStoreInfo : CachedModel<DesiredModel>
{
    protected override async Task ThreadSafeUpdateAsync()
    {
        // make the trip to db and Blob service
        Model = some result
    }

    protected override bool NeedsUpdate()
    {
        return someLogicToDecideIfNeedsUpdate;
    }
}

наконец, в контроллере asp все, что мне нужно сделать, это:

[HttpGet]
public async Task<DesiredModel> GetStoreInfo()
{
    return await cachedStoreInfo.GetModel();
}

Это правильная реализация?и это даже необходимо, или есть более разумный способ достичь этого?получение меток времени из BLOB-объекта было основной причиной, по которой я думал о кешировании результата

1 Ответ

0 голосов
/ 25 января 2019

Ваша реализация выглядит правильно.Конечно, экземпляр CachedStoreInfo должен быть синглтоном в требуемой области (как я понимаю, в вашем случае это должен быть синглтон в области применения).

могут ли другие потоки войти сюда после того, как первый уже обновил объект?

Как отметил Кевин Госс, сюда могут войти другие потоки.Ваш второй чек на NeedsUpdate() является частью Дважды проверенного шаблона блокировки .И это может быть хорошей оптимизацией.

и это даже необходимо, или есть более разумный способ добиться этого?

Что касается меня, ваша реализация минималистична и умнадостаточно

...