Индексы в памяти - PullRequest
       3

Индексы в памяти

8 голосов
/ 19 мая 2011

У меня есть концепция Session, которая хранит объекты в различных состояниях.

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

Поэтому я хотел бы представить концепцию индексов в сеансе.

Что-то вроде ...

public IDictionary<K, V> GetIndex<K, V>(Func<V, K> keySelector)

Однако я не уверен в том, как проверить «равенство» такого функционала. Очевидно, что я хочу, чтобы индекс строился только при первом вызове GetIndex и последующих вызовах, чтобы не строить его снова.

Как я должен отображать их внутренне, чтобы выполнять поиск существования индекса?

IDictionary<???, IDictionary<K, V>> indexes = ...

В основном, как я должен хранить ??? Может быть, я не могу сделать это с помощью Func, но, возможно, есть какой-то другой способ.

Ответы [ 3 ]

1 голос
/ 19 мая 2011

Вы можете использовать Expression<Func<K,V>>, а затем Compile() выражение, когда вам нужно выполнить.

Чтобы проверить равенство, взгляните на следующий вопрос:
Как проверить, совпадают ли два выражения >

В качестве альтернативы, вы можете дать индексам имя и продолжать использовать делегат:

public IDictionary<K, V> GetIndex<K, V>(string indexName, Func<V, K> keySelector)

IDictionary<string, IDictionary<K, V>> indexes = ..
1 голос
/ 19 мая 2011

Сравнение выражений в циклах может занять больше времени, чем выбор из словаря. Как уже указывалось в ветке, существуют способы их сравнения, но очень трудоемкие и не точные:

x => x.Key == 1

против

y => y.Key == 1

против

int value = 1
x => x.Key == value

даст ложь

Так что создание индексов ad hoc не является хорошим решением.

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

Что-то вроде (псевдоC # ode):

static class Indexfactory {
   private static Dictionary<IndexcreationParams,Expression> ...

   // more of these as required
   public static Expression getIndex<Tret,P1,P2,P3,...>(IndexType type, P1 p1,P2 p2,P3 p3...) {       
     // create expression from template with the supplied parameters
     // if not already existent, else rerturn it from static storage
     // store expression in some private storage
   }
}

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

1 голос
/ 19 мая 2011

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

Если ваши запросы являются строками, вы, вероятно, можете просто использовать строку.Функция GetHashCode для вычисления простого хэша в строковых данных.Если ваши запросы являются запросами Linq, .GetHashCode, вероятно, не будет работать, если Linq специально не переопределит этот метод для вычисления хеша по дереву выражений вместо указателя экземпляра объекта по умолчанию.Реализация по умолчанию .GetHashCode просто возвращает значение, полученное из идентификатора экземпляра объекта в памяти, без учета содержимого данных объекта.

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

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

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