Здравствуйте, Ikemefula, Вы писали:
I>Потому что память пока что не бесконечная и GC требует больших затрат времени. У меня например структуры где требуется доступ по ключу, живут почти все время, что и приложение.
Так это нормально. А как ты хотел ? Удалить одно значение и освободить десять байт моментально ?
I>У тебя шота все за O(1), чтото не так с тестами. Код тестов ты не выкладывал ?
Такого плана тест. rand.bin это заархивированый фильм, источник случайной последовательности для ключей.
Тест такого плана.
Здравствуйте, PC_2, Вы писали:
I>>Потому что память пока что не бесконечная и GC требует больших затрат времени. У меня например структуры где требуется доступ по ключу, живут почти все время, что и приложение.
PC_>Так это нормально. А как ты хотел ? Удалить одно значение и освободить десять байт моментально ?
Примерно так. Есть мега-деревья, которые так и работают.
I>>У тебя шота все за O(1), чтото не так с тестами. Код тестов ты не выкладывал ?
PC_>Такого плана тест. rand.bin это заархивированый фильм, источник случайной последовательности для ключей. PC_>Тест такого плана.
Я не понял, key это uint ? Контейнер для таких ключей я накидаю за полчаса с перерывом на обед
Re[8]: std::map VS Dictionary.NET VS SortedDictionary.NET VS
Здравствуйте, Ikemefula, Вы писали:
PC_>>Так это нормально. А как ты хотел ? Удалить одно значение и освободить десять байт моментально ? I>Примерно так. Есть мега-деревья, которые так и работают.
Не, они так не работают. Читать для чего делается Shrink в СУБД.
I>Я не понял, key это uint ? Контейнер для таких ключей я накидаю за полчаса с перерывом на обед
Накидай, пока стандартные структуры сливают в разы, некоторые особо неприлично в 50+ раз.
Твоя задача сохранить 20 млн пар Int32/Int32 в структуре данных в 200 мегабайт
и обеспечить быстрый поиск по такой структуре.
Структура моделирует например телефонный справочник, где ключ номер телефона, значение указатель на имя абонента.
"Вся страна играть в футбол умеет, лишь мы 11 человек играть не умеем"(с)КВН
Re[9]: std::map VS Dictionary.NET VS SortedDictionary.NET VS
Я так понял, что ключи — всегда инты? Ну, так не интересно.
И уж тем более сравнение по скорости с универсальным Dictionary не совсем корректное.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[5]: std::map VS Dictionary.NET VS SortedDictionary.NET VS
Здравствуйте, Eugeny__, Вы писали:
E__>Здравствуйте, PC_2, Вы писали:
PC_>>>>ап WH>>>Код где?
PC_>>Код не опен сорц. PC_>>Опенсорснул я только одну из тестовых версий. PC_>>http://www.sql.ru/forum/actualfile.aspx?id=12509735
E__>Я так понял, что ключи — всегда инты? Ну, так не интересно. E__>И уж тем более сравнение по скорости с универсальным Dictionary не совсем корректное.
Согласен маловато инта.
Но с другой стороны это краеугольный камень. Например чтобы хранить Гуиды 16 байт, можно брать первые четыре байта
а все остальное хранить списками колизий. Ну как самый простой вариант.
И получать теже 40-50 наносекунд на вставку, и 40-50 наносекунд на поиск...
"Вся страна играть в футбол умеет, лишь мы 11 человек играть не умеем"(с)КВН
Re[9]: std::map VS Dictionary.NET VS SortedDictionary.NET VS
Здравствуйте, PC_2, Вы писали:
PC_>Здравствуйте, Ikemefula, Вы писали:
PC_>>>Так это нормально. А как ты хотел ? Удалить одно значение и освободить десять байт моментально ? I>>Примерно так. Есть мега-деревья, которые так и работают.
PC_>Не, они так не работают.
Работают. Как, кстати говоря, будет работать твой контейнер если ключи будут неуникальными ?
I>>Я не понял, key это uint ? Контейнер для таких ключей я накидаю за полчаса с перерывом на обед
PC_>Накидай, пока стандартные структуры сливают в разы, некоторые особо неприлично в 50+ раз.
Стандартные затачиваются под стандартные сценарии. Подо что ты заточил своё дерево — не ясно. По тем тестам и результатам ничего не ясно, где это можно использовать и какие у него свойства.
PC_>Твоя задача сохранить 20 млн пар Int32/Int32 в структуре данных в 200 мегабайт
То есть, ты предлагаешь задачу, которая сэкономит 100-200мб относительно твоей реализации ?
Покажи тест на .net, будем искать ошибку
Re[10]: std::map VS Dictionary.NET VS SortedDictionary.NET V
Здравствуйте, Ikemefula, Вы писали:
I>Покажи тест на .net, будем искать ошибку
На преведущей странице есть с# код.
Кстате Джуди ареям я по предварительным данным, слил 50% по поиску.
Но выиграл в два раза по скорости вставок.
Таки дела.
20 тыс строк кода на Си и пацаны с Хевлет Паккарда всеже сделали свое дело
Чтож, будем думать.
"Вся страна играть в футбол умеет, лишь мы 11 человек играть не умеем"(с)КВН
Re[11]: std::map VS Dictionary.NET VS SortedDictionary.NET V
Здравствуйте, PC_2, Вы писали:
PC_>Здравствуйте, Ikemefula, Вы писали:
I>>Покажи тест на .net, будем искать ошибку
PC_>На преведущей странице есть с# код. PC_>Кстате Джуди ареям я по предварительным данным, слил 50% по поиску. PC_>Но выиграл в два раза по скорости вставок. PC_>Таки дела.
PC_>20 тыс строк кода на Си и пацаны с Хевлет Паккарда всеже сделали свое дело PC_>Чтож, будем думать.
Вот тест на i5, размеро слова 64 бита, i686-apple-darwin11-llvm-gcc-4.2
word size = 8 numkeys = 1000000
generate keys
insert keys first = 1799781661ll last = 1932781528ll
insert time = 0.137306005 avg = 0.000000137 memory = 18.97 mb
read time = 0.011178000 avg = 0.000000011
range time = 0.041843001 avg = 0.000000042 items = 1000000
#include"Judy.h"#include <stdlib.h>
#include <time.h>
#define NUMKEYS 1000000
int main(int argc,char* argv[])
{
Pvoid_t array = NULL;
PJError_t err = 0;
printf("word size = %lu numkeys = %d\n",sizeof(Word_t),NUMKEYS);
Word_t* keys = malloc(NUMKEYS*sizeof(Word_t));
Word_t* range = malloc(NUMKEYS*sizeof(Word_t));
srand(clock());
printf("generate keys\n");
Word_t startvalue = 6094748957;
int i = 0;
for (i = 0; i < NUMKEYS; ++i)
{
keys[i] = startvalue + (i * 133);
}
printf("insert keys first = %ull last = %ull\n",keys[0],keys[NUMKEYS-1]);
clock_t start,stop;
start = clock();
for (i = 0; i < NUMKEYS; ++i)
{
JudyLIns(&array,keys[i],&err);
}
stop = clock();
Word_t memused = JudyLMemUsed(array);
printf("insert time = %0.9f avg = %0.9f memory = %0.2f mb\n",
(float)(stop-start)/CLOCKS_PER_SEC,
((float)(stop-start)/CLOCKS_PER_SEC)/NUMKEYS,
(float)memused / 1024 / 1024
);
start = clock();
for(i = 0; i < NUMKEYS; ++i)
{
JudyLGet(&array,keys[i],&err);
}
stop = clock();
printf("read time = %0.9f avg = %0.9f\n",
(float)(stop-start)/CLOCKS_PER_SEC,
((float)(stop-start)/CLOCKS_PER_SEC)/NUMKEYS
);
start = clock();
int j = 0;
Word_t Index = 0;
Word_t* PValue = NULL;
JLF(PValue,array,Index);
while (PValue != NULL)
{
range[j++] = Index;
JLN(PValue,array,Index);
}
stop = clock();
printf("range time = %0.9f avg = %0.9f items = %d\n",
(float)(stop-start)/CLOCKS_PER_SEC,
((float)(stop-start)/CLOCKS_PER_SEC)/NUMKEYS,
j
);
return 0;
}
Re[12]: std::map VS Dictionary.NET VS SortedDictionary.NET V
Спасибо за тест!
Такой вопрос, Джуди проверяет ключи на выход за диапазон ?
Ато вроде как на .NET обертке добавление двух одинаковых ключей убило всю структуру.
"Вся страна играть в футбол умеет, лишь мы 11 человек играть не умеем"(с)КВН
Re[12]: std::map VS Dictionary.NET VS SortedDictionary.NET V
Теперь по тесту.
Ну прежде всего бросается в глаза феншуйная работа кешей процессора для псевдослучайной последовательности.
Перемножать простые числа, это все хорошо, но куда больше процессор страдает если
адреса прыгают по непредсказуемым законам. Для этого я брал поток байт из заархивированого файла видео
и формировал из них ключи.
Word_t startvalue = 6094748957; R> int i = 0; R> for (i = 0; i < NUMKEYS; ++i) R> { R> keys[i] = startvalue + (i * 133); R> }
R>
R>word size = 8 numkeys = 1000000
R>generate keys
R>insert keys first = 1799781661ll last = 1932781528ll
R>insert time = 0.137306005 avg = 0.000000137 memory = 18.97 mb
R>read time = 0.011178000 avg = 0.000000011
R>range time = 0.041843001 avg = 0.000000042 items = 1000000
R>
Теперь взял псевдослучайную последовательность, както так
(сорри за муссор в коде, много тестовой инфы):
Здравствуйте, minorlogic, Вы писали:
M>Если поиск и вставка константные и данные отсортированны (с возможностью быстрого обхода), то это революция в CS
Ну да, немного занятно получилось.
Quick sort = Inserts + Full scan по сортированым данным.
Тоесть чтобы отсортировать допустим большой обьем данных,
можно вставить в структуру и сделать фуллскан и по времени даже может быть
какойто минимальный выиграш Эдакий побочный эффект алгоритма.
Правда следует отметить справедливости ради, что второй алгоритм с структурой данных,
будет требовать дополнительную память. Квик сорт же не ест доп память.
"Вся страна играть в футбол умеет, лишь мы 11 человек играть не умеем"(с)КВН
Re[3]: std::map VS Dictionary.NET VS SortedDictionary.NET VS HArray
Здравствуйте, PC_2, Вы писали:
PC_>Здравствуйте, Serginio1, Вы писали:
S>>Здравствуйте, PC_2, Вы писали: S>>Посмотри Б деревья http://rsdn.ru/article/alg/tlsd.xml
PC_>Разные Б деревья в плане скорости поиска/вставки не интересны.
Ну почему же. Б+ деревья на больших данных немного уступают Хэш таблицам. При примененийй данных типа курсора
и вставок типа NavigateOrInsertDefault можно это время сократить в 2 раза. При больших данных и поиск происходит быстрее, т.к. верхние уровни находятся в кэше процессора. Так как на практике в основном происходит поиск а не вставки, то возможно дополнительно в поиску подключать и хэш таблицу уоторая бы хранила Ключ и Страницу на которой находится элемент. Это значительно сократит поиск.
и солнце б утром не вставало, когда бы не было меня
Re[4]: std::map VS Dictionary.NET VS SortedDictionary.NET VS HArray
Здравствуйте, Serginio1, Вы писали:
PC_>>Разные Б деревья в плане скорости поиска/вставки не интересны. S> Ну почему же. Б+ деревья на больших данных немного уступают Хэш таблицам. При примененийй данных типа курсора
На больших обьемах данных у хештаблиц коллизии ростут в экспоненциальном порядке.
Это первый недостаток. Второй, они не сортируют ключи и не позволяют делать выборки по диапазону.
Но по скорости вставки/выборки разные подвиды бинарных деревьев далеко или очень далеко.
К слову сказать у меня одна из модификаций префиксных деревьев и здесь тоже можно верхние уровни
размещать в ОЗУ.
S>и вставок типа NavigateOrInsertDefault можно это время сократить в 2 раза. При больших данных и поиск происходит быстрее, т.к. верхние уровни находятся в кэше процессора. Так как на практике в основном происходит поиск а не вставки, то возможно дополнительно в поиску подключать и хэш таблицу уоторая бы хранила Ключ и Страницу на которой находится элемент. Это значительно сократит поиск.
Глянул Вашу реализацию.
Ну чисто визуально, сравните Вашу функцию поиска по ключу:
public bool NavigateKey(K key)
{
// Устанавливаем индекс элемента в 0.
_currentElementIndex = 0;
// Если есть второй уровень...if (_pageCount > 1)
{
// Перебираем граниint hi = _pageCount - 1;
int lo = 0;
while (lo <= hi)
{
int i = (lo + hi) >> 1;
int result = _comparer.Compare(NodeArray[i].Key, key);
if (result < 0)
lo = i + 1;
else
{
hi = i - 1;
if (result == 0)
{
// Ключ найден на 2 уровне. Устанавливаем текущую
// страницу CurrentLeafPage.
_currentPageIndex = i;
CurrentLeafPage = NodeArray[_currentPageIndex].ChildPage;
_selected = true;
return true;
}
}
}
// Ключ не найден на 2 уровне.
// Проверяем на возможность того, что искомый ключ –
// наименьший из имеющихся в объекте.if (hi < 0)
{
// Данный ключ меньше наименьшего хранимого ключа.
// Встаем на самый первый элемент двухуровневого массива
_currentPageIndex = 0;
CurrentLeafPage = NodeArray[_currentPageIndex].ChildPage;
_selected = false;
// Возвращаем информацию о том, что ключ не найден.return false;
}
else
{
// Данный ключ попадает в диапазон ключей нижележащей страницы.
// Изменяем текущую страницу CurrentLeafPage на найденную дочернюю
// страницу
CurrentLeafPage = NodeArray[_currentPageIndex].ChildPage;
// Устанавливаем текущий индекс ключа на листовой странице в 1,
// т.к. 0 уже проверяли.
_currentElementIndex = 1;
}
}
// Пытаемся найти индекс искомого ключа или индекс, в котором он должен
// был находиться.
hi = CurrentLeafPage.Count - 1;
lo = _currentElementIndex;
while (lo <= hi)
{
int i = (lo + hi) >> 1;
int result = _comparer.Compare(CurrentLeafPage.PageItems[i].Key, key);
if (result < 0)
lo = i + 1;
else
{
hi = i - 1;
if (result == 0)
{
// Нашли!
_currentElementIndex = i;
_selected = true;
return true;
}
}
}
// Не нашли...
_selected = false;
// Помещаем в _currentElementIndex позицию в которую
// можно добавить элемент с искомым ключом.
_currentElementIndex = lo;
return false;
}
Теперь чисто визуально, сколько нужно первой реализации выполнить процессорных комманд, сделать дополнительных вызовов функций, копирований и тд
и моей реализации которая извлекает значение по ключу за О(1), внезависимости там 100 ключей или 100 млрд ключей.
Количество итераций в цикле зависит от длины ключа, например для ключа в 8 символов будет всегда константно 4 итерации.
Как видите, здесь уж совсем экономный вариант.
Поиск чуть тяжелее чем прямое взятие элемента из массива по индексу и в некоторых случаях разгоняется до абсолютно
фантастических 2 наносекунд на один поиск (500 млн поисков в секунду).
"Вся страна играть в футбол умеет, лишь мы 11 человек играть не умеем"(с)КВН
Re[5]: std::map VS Dictionary.NET VS SortedDictionary.NET VS HArray
PC_>Теперь чисто визуально, сколько нужно первой реализации выполнить процессорных комманд, сделать дополнительных вызовов функций, копирований и тд
Ну я предлагал использовать Хэш таблицу для ключей в котором хранится ключ и страница Б+ дерева Что бы производить поиск не по дереву а на странице.
Но это не суть. Проблема при увеличении объемов данных не попадающих в Кэш процессора сильно уже зависит от медленной памяти. А соотношение времени вставки поиска Б+ деревья и Хэш таблицы остаются константными. Кстати если видел реализацию NavigateOrInsertDefault то там запоминаентся текущая позиция и при изменении значения вторичный поиск не производится. А по поводу выборки Б+ деревьев, то это прохождение по масииву. Обычно нужны выборки по диапозону, поиск на меньше или больше значения без равно итд. Все то, что используется в Базе. А также сравнение двух таблиц по индексам где сравнение идет не по поиску ключа а по сравнению текущих значений и продвижению по таблице с меньшим ключем, при равном двигаются оба курсора.
и солнце б утром не вставало, когда бы не было меня