Как обновить синглтон в C # - PullRequest
5 голосов
/ 16 марта 2011

У меня есть синглтон, который выбирает из БД, следовательно, это дорогая загрузка.Он загружен с отложенной загрузкой.

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

данные являются БД и очень дорогими, поэтому я хочу обновитьтолько один раз, если у меня есть одновременные звонки.(то есть, если я получаю 500 вызовов для обновления, я хочу перезапустить обновление только один раз)

public static PageData Instance
    {
        get
        {
            if (m_Instance == null)
            {
                lock (instanceLock)
                {
                    if (m_Instance == null)
                    {
                        m_Instance = new PageData();
                    }
                }
            }
            return m_Instance;
        }
    }


public void ReSync()
        {                         
            lock (instanceLock)
            {
                /* Setting to null to force the Instance to re-build */
                m_Instance = null;
                PageData pData = Instance;
            }
        }

спасибо

Ответы [ 7 ]

2 голосов
/ 16 марта 2011

Это немного неверно, ваш

if (m_Instance == null)

действительно должно быть внутри замка.

Извините, не заметил этого.

Ничего не встроено, что может заставить других клиентов молча отказаться от звонков, если вы уже обновляетесь. Таймауты сгенерируют исключение, я думаю. Возможно, используйте устаревший DateTime, который вы можете проверить, чтобы избежать обновления для вызывающих абонентов.

1 голос
/ 17 марта 2011

В моем понимании это должно работать.

Вот мой код:

private static instanceLock = new object();
private static _refreshing = true;

public static PageData Instance
    {
        get
        {
            if (_refreshing)
            {
                lock (instanceLock)
                {
                    if (_refreshing)
                    {
                        m_Instance = new PageData();
                        _refreshing = false; //now allow next refreshes.
                    }
                }
            }
            return m_Instance;
        }
    }


public void ReSync()
        {
            if (!_refreshing)                         
                lock (instanceLock)
                {
                    if (!_refreshing)
                    {
                        _refreshing = true; //don't allow refresh until singleton is called.
                    }
                }
        }
1 голос
/ 16 марта 2011

Помимо блокировки с двойной проверкой (нарушение, по-видимому, оно работает , но я все еще нахожу это не особенно симпатичным), если у вас есть доступ на запись в m_Instance, почему бы и нетпросто установите его в новый PageData () тут же в ReSync?

0 голосов
/ 17 марта 2011

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

Если следующий запрос такой же, как и предыдущий обналиченный (вы сами определяете критерии «идентичности»),вызывающая сторона получит вместо этого кэшированную копию.В действительности это означает, что нет нового соединения с БД.Просто запрос памяти.Если действительные критерии кэширования прошли, например, 30 минут), следующий запрос к базе данных (в течение другого периода времени).

Требуется память, но он чрезвычайно быстр и рекомендуется в сценариях, где данные используются повторно.

0 голосов
/ 16 марта 2011

Как я понимаю, вы ожидаете одновременных вызовов метода Resync?Это действительно не должно произойти, если вы звоните только один раз из 500 запросов от клиентов.Тем не менее, может быть, тогда лучше не блокировать instanceLock, потому что тогда синглтон все равно будет повторно создан несколько раз, только не в одно и то же время.

0 голосов
/ 16 марта 2011

Если вы хотите, чтобы он соответствовал модели памяти ECMA, я думаю, что реализация должна выглядеть примерно так (при условии, что m_Instance не является энергозависимым):

public static PageData Instance
{
    get
    {
        PageData instance = Thread.VolatileRead(ref m_Instance);
        if (instance == null)
        {
            lock (instanceLock)
            {
                instance = Thread.VolatileRead(ref m_Instance);
                if (instance == null)
                {
                    instance = new PageData();
                    Thread.VolatileWrite(ref m_Instance, instance);
                }
            }
        }

        return instance;
    }
}

public void ReSync()
{
    /* Setting to null to force the Instance to re-build */
    Thread.VolatileWrite(ref m_Instance, null);
    PageData pData = Instance;
}

Если вы определили m_Instanceбыть изменчивым есть только одно главное отличие.m_Instance необходимо прочитать в локальную переменную перед выполнением нулевой проверки, поскольку метод ReSync() может установить для совместно используемой переменной значение null.Я также снял блокировку с ReSync(), так как она не нужна.Гонка за инициализацию нового экземпляра безопасна.

0 голосов
/ 16 марта 2011

Как насчет того, чтобы включить элемент «lastRefreshed», который вы также проверяете и блокируете при обновлении. Так что, если последнее обновление произошло в течение X времени, оно не произойдет снова?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...