Очередь фиксированного размера с вытеснением старых
От: Аноним  
Дата: 18.01.11 18:23
Оценка:
Требуется отображать последние 10000 элементов. Записи порождаются достаточно быстро — около 1000 в минуту их нужно логировать.

Пока вижу варант с Dictionary<int, MeasureData > и переменной с индексом как курсор текущей позиции.
Но есть несколько проблем — для новых значений создается новый MeasureData со своим DateTime что может съесть память. А также выборка из такого списка не очень удобна учитывая что нужно еще по дате в обратном порятке сортировать — лишние расчеты.

Есть ли готовые списки для этого ?
Re: Очередь фиксированного размера с вытеснением старых
От: samius Япония http://sams-tricks.blogspot.com
Дата: 18.01.11 18:59
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Требуется отображать последние 10000 элементов. Записи порождаются достаточно быстро — около 1000 в минуту их нужно логировать.


А>Пока вижу варант с Dictionary<int, MeasureData > и переменной с индексом как курсор текущей позиции.

А>Но есть несколько проблем — для новых значений создается новый MeasureData со своим DateTime что может съесть память. А также выборка из такого списка не очень удобна учитывая что нужно еще по дате в обратном порятке сортировать — лишние расчеты.

А>Есть ли готовые списки для этого ?

Есть стандартный FIFO контейнер — Queue<T>. Сортировать не надо, если складывать по мере порождения данных.
Re[2]: Очередь фиксированного размера с вытеснением старых
От: Аноним  
Дата: 18.01.11 19:28
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Аноним, Вы писали:


А>>Требуется отображать последние 10000 элементов. Записи порождаются достаточно быстро — около 1000 в минуту их нужно логировать.


А>>Пока вижу варант с Dictionary<int, MeasureData > и переменной с индексом как курсор текущей позиции.

А>>Но есть несколько проблем — для новых значений создается новый MeasureData со своим DateTime что может съесть память. А также выборка из такого списка не очень удобна учитывая что нужно еще по дате в обратном порятке сортировать — лишние расчеты.

А>>Есть ли готовые списки для этого ?

S>Есть стандартный FIFO контейнер — Queue<T>. Сортировать не надо, если складывать по мере порождения данных.

Не совсем то. Ниже тестовый пример, может я неправильно с ней работаю.
Dequene будет съедать элемент, и второму потоку оно не достанется. самое старое значение должно вытесняться при вставке нового элемента а не при чтении.
Т.е. допустим нам не 10000 нужно записей а иметь "окно" только 5 последних записей.
Соотвественно сначала должно вывестись :

5,4,3,2,1 потом 6,5,4,3,2 , потом 7,6,5,4,3
в обоих потоках.



   class Program
    {
        static Queue<int> q;
        static object syncObj = new object();

        static void ShowLast5()
        {

                while (true)
                {
                    // это блокирока чтоб 2 потока по очереди показывали результат 5 сек кажды
                    lock( syncObj )
                    {
                        Console.Clear();
                        Console.WriteLine(string.Format("Last 5 Records from Thread {0}: ", System.Threading.Thread.CurrentThread.ManagedThreadId));
                        foreach (var i in q)
                            Console.WriteLine(i);

                        System.Threading.Thread.Sleep(5000);
                    }                
                }
        }

        static int newitem;
        static void Generate()
        {
            while (true)
            {
                q.Enqueue(newitem);
                newitem++;
                System.Threading.Thread.Sleep(15000);
            }

        }


        static void Main(string[] args)
        {
            
            q = new Queue<int>(5);
            q.Enqueue(1);
            q.Enqueue(2);
            q.Enqueue(3);
            q.Enqueue(4);
            q.Enqueue(5);

            newitem = 6;

            var t1 = new System.Threading.Thread(Generate);
            t1.Start();

            var t2 = new System.Threading.Thread(ShowLast5);
            t2.Start();
            var t3 = new System.Threading.Thread(ShowLast5);
            t3.Start();

            Console.ReadKey();
        }
    }
Re[3]: Очередь фиксированного размера с вытеснением старых
От: samius Япония http://sams-tricks.blogspot.com
Дата: 18.01.11 19:45
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, samius, Вы писали:


А>>>Есть ли готовые списки для этого ?

S>>Есть стандартный FIFO контейнер — Queue<T>. Сортировать не надо, если складывать по мере порождения данных.

А>Не совсем то. Ниже тестовый пример, может я неправильно с ней работаю.

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

А>Т.е. допустим нам не 10000 нужно записей а иметь "окно" только 5 последних записей.

А>Соотвественно сначала должно вывестись :

А>5,4,3,2,1 потом 6,5,4,3,2 , потом 7,6,5,4,3

А>в обоих потоках.

Не понял. Требуется что бы один и тот же контейнер, изменяемый в одном потоке отыграл все свои состояния в других потоках, которые выводят в консоль элементы?
Если так, то мне неясно, как здесь поможет Dictionary...

А>
А>   class Program
А>    {
А>    }
А>

В коде ошибки синхронизации, кроме того по нему не понятно, какая задача решается.
Re: Очередь фиксированного размера с вытеснением старых
От: dims12 http://www.relativity.ru
Дата: 18.01.11 20:12
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Пока вижу варант с Dictionary<int, MeasureData > и переменной с индексом как курсор текущей позиции.


Не совсем понятно, почему не подходит обыкновенный List<>?
Re[2]: Очередь фиксированного размера с вытеснением старых
От: Аноним  
Дата: 18.01.11 21:09
Оценка:
Здравствуйте, dims12, Вы писали:

D>Здравствуйте, Аноним, Вы писали:


А>>Пока вижу варант с Dictionary<int, MeasureData > и переменной с индексом как курсор текущей позиции.


D>Не совсем понятно, почему не подходит обыкновенный List<>?


тормозить будет при вставке элемента в начало или наоборот при удалении из начала.
Re[4]: Очередь фиксированного размера с вытеснением старых
От: Аноним  
Дата: 18.01.11 21:14
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Аноним, Вы писали:


А>>Здравствуйте, samius, Вы писали:


А>>>>Есть ли готовые списки для этого ?

S>>>Есть стандартный FIFO контейнер — Queue<T>. Сортировать не надо, если складывать по мере порождения данных.

А>>Не совсем то. Ниже тестовый пример, может я неправильно с ней работаю.

А>>Dequene будет съедать элемент, и второму потоку оно не достанется. самое старое значение должно вытесняться при вставке нового элемента а не при чтении.
S>В стартовом сообщении ничего о потоках не было...

А>>Т.е. допустим нам не 10000 нужно записей а иметь "окно" только 5 последних записей.

А>>Соотвественно сначала должно вывестись :

А>>5,4,3,2,1 потом 6,5,4,3,2 , потом 7,6,5,4,3

А>>в обоих потоках.

S>Не понял. Требуется что бы один и тот же контейнер, изменяемый в одном потоке отыграл все свои состояния в других потоках, которые выводят в консоль элементы?

S>Если так, то мне неясно, как здесь поможет Dictionary...

А>>
А>>   class Program
А>>    {
А>>    }
А>>

S>В коде ошибки синхронизации, кроме того по нему не понятно, какая задача решается.

задача простая видеть последние N записей из разных потоков, старые записи должны из списка/очереди удаляться иначе их накопится очень много.

решение на Dictionary вижу примерно следующее.


public class MyQuene
{

    private Dictionary<int, MeasureData> quene;
    private int currentItem = 0;
    private int queneCapacity = 10000;

    public PushNewMeasure( p1, p2, p3 )
    {
        if ( currentItem >= queneCapacity )
        {
           currentItem=0;
        }

        quene[ currentItem ] = new MeasureData( p1, p2, p3 );
        currentItem++;
    }

    public MeasureData[] GetMeasures()
    {       
        return
        quene.Skip( currentItem ).Take( queneCapacity - currentItem).
          Union( quene.Take( currentItem ) )
          .Select ( i => i.Value).Reverse().ToArray();
    }
}
Re[2]: Очередь фиксированного размера с вытеснением старых
От: Аноним  
Дата: 18.01.11 21:23
Оценка:
Здравствуйте, dims12, Вы писали:

D>Здравствуйте, Аноним, Вы писали:


А>>Пока вижу варант с Dictionary<int, MeasureData > и переменной с индексом как курсор текущей позиции.


D>Не совсем понятно, почему не подходит обыкновенный List<>?


Вот блин. Оказывается он ничуть не тормозной
Вполне шустро работает. Меньше миллисекунды..196 тиков всего.
А он не двигает все элементы при удаленни чтоли ?
Re[5]: Очередь фиксированного размера с вытеснением старых
От: samius Япония http://sams-tricks.blogspot.com
Дата: 18.01.11 21:24
Оценка:
Здравствуйте, Аноним, Вы писали:

А>задача простая видеть последние N записей из разных потоков, старые записи должны из списка/очереди удаляться иначе их накопится очень много.


Полагаю, что с этого надо было начать.

А>решение на Dictionary вижу примерно следующее.


А>

А>public class MyQuene
А>{

А>    private Dictionary<int, MeasureData> quene;
А>    private int currentItem = 0;
А>    private int queneCapacity = 10000;

А>    public PushNewMeasure( p1, p2, p3 )
А>    {
А>        if ( currentItem >= queneCapacity )
А>        {
А>           currentItem=0;
А>        }

А>        quene[ currentItem ] = new MeasureData( p1, p2, p3 );
А>        currentItem++;
А>    }

А>    public MeasureData[] GetMeasures()
А>    {       
А>        return
А>        quene.Skip( currentItem ).Take( queneCapacity - currentItem).
А>          Union( quene.Take( currentItem ) )
А>          .Select ( i => i.Value).Reverse().ToArray();
А>    }
А>}

А>

Вообще говоря это решение обладает недостатками:
*) записи не удаляются
*) синхронизация отсутствует как класс
*) при добавлении очередного элемента и одновременном выполнении GetMeasures неминуемо исключение
*) записи не упорядоченны и берутся не последние
Re[3]: Очередь фиксированного размера с вытеснением старых
От: samius Япония http://sams-tricks.blogspot.com
Дата: 18.01.11 21:26
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, dims12, Вы писали:


D>>Здравствуйте, Аноним, Вы писали:


А>>>Пока вижу варант с Dictionary<int, MeasureData > и переменной с индексом как курсор текущей позиции.


D>>Не совсем понятно, почему не подходит обыкновенный List<>?


А>Вот блин. Оказывается он ничуть не тормозной

А>Вполне шустро работает. Меньше миллисекунды..196 тиков всего.
А>А он не двигает все элементы при удаленни чтоли ?
Двигает. А Queue — нет.
Re[3]: Очередь фиксированного размера с вытеснением старых
От: LaptevVV Россия  
Дата: 18.01.11 21:27
Оценка:
Здравствуйте, Аноним, Вы писали:
А>>>Пока вижу варант с Dictionary<int, MeasureData > и переменной с индексом как курсор текущей позиции.
D>>Не совсем понятно, почему не подходит обыкновенный List<>?
А>тормозить будет при вставке элемента в начало или наоборот при удалении из начала.
Читайте матчасть. Вставка и удаление из списка выполняются за константное время.
Кроме того, то, что я тут прочитал, наводит меня на мысль, что вполне можно обйтись стандартным деком, который тоже вставку и удаление на концах делает за константное время. А то, что вы тут говорите о потоках — это стандартная задача читатели-писатели. Требует синхронизации доступа к буферу-контейнеру. Это — средствами API — в С++ стандартных средств пока нет.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: Очередь фиксированного размера с вытеснением старых
От: samius Япония http://sams-tricks.blogspot.com
Дата: 18.01.11 21:30
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, Аноним, Вы писали:

А>>>>Пока вижу варант с Dictionary<int, MeasureData > и переменной с индексом как курсор текущей позиции.
D>>>Не совсем понятно, почему не подходит обыкновенный List<>?
А>>тормозить будет при вставке элемента в начало или наоборот при удалении из начала.
LVV>Читайте матчасть. Вставка и удаление из списка выполняются за константное время.
Речь о дотнете, в нем List-ом называется динамический массив. Соответственно время вставки/удаления линейное.

LVV>Требует синхронизации доступа к буферу-контейнеру. Это — средствами API — в С++ стандартных средств пока нет.

Тема ведь в донтене
Re[6]: Очередь фиксированного размера с вытеснением старых
От: Аноним  
Дата: 18.01.11 21:33
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Аноним, Вы писали:


А>>задача простая видеть последние N записей из разных потоков, старые записи должны из списка/очереди удаляться иначе их накопится очень много.


S>Полагаю, что с этого надо было начать.


А>>решение на Dictionary вижу примерно следующее.


А>>

А>>public class MyQuene
А>>{

А>>    private Dictionary<int, MeasureData> quene;
А>>    private int currentItem = 0;
А>>    private int queneCapacity = 10000;

А>>    public PushNewMeasure( p1, p2, p3 )
А>>    {
А>>        if ( currentItem >= queneCapacity )
А>>        {
А>>           currentItem=0;
А>>        }

А>>        quene[ currentItem ] = new MeasureData( p1, p2, p3 );
А>>        currentItem++;
А>>    }

А>>    public MeasureData[] GetMeasures()
А>>    {       
А>>        return
А>>        quene.Skip( currentItem ).Take( queneCapacity - currentItem).
А>>          Union( quene.Take( currentItem ) )
А>>          .Select ( i => i.Value).Reverse().ToArray();
А>>    }
А>>}

А>>

S>Вообще говоря это решение обладает недостатками:
S>*) записи не удаляются
так их и не нужно удалять, их всегда ровно 10000. Просто старые перезаписываются новыми а не вставляются/удаляются.

S>*) синхронизация отсутствует как класс

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

S>*) при добавлении очередного элемента и одновременном выполнении GetMeasures неминуемо исключение

это из п.2. и следует поставить lock{} большого труда не составит

S>*) записи не упорядоченны и берутся не последние

записи как раз упорядочены по Index в порядке добавления, допустим index текущий = 5000, соотвественно запрос выберет с 5001-10000 и сделает union с 1-5000 записи — получится список в хронологическом порядке — ему делается reverse().


Но в общем мне понравилось обычное решение с list.Insert(0,...) и list.RemoveAt(1001) его и буду использовать с большой вероятностью
Re[7]: Очередь фиксированного размера с вытеснением старых
От: samius Япония http://sams-tricks.blogspot.com
Дата: 18.01.11 21:37
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, samius, Вы писали:


S>>Вообще говоря это решение обладает недостатками:

S>>*) записи не удаляются
А>так их и не нужно удалять, их всегда ровно 10000. Просто старые перезаписываются новыми а не вставляются/удаляются.
С чего бы это они перезаписываются?

S>>*) синхронизация отсутствует как класс

А>ну я не стал загромождать код синхронизацией тут как бы главное алгоритм очереди

S>>*) при добавлении очередного элемента и одновременном выполнении GetMeasures неминуемо исключение

А>это из п.2. и следует поставить lock{} большого труда не составит

S>>*) записи не упорядоченны и берутся не последние

А>записи как раз упорядочены по Index в порядке добавления, допустим index текущий = 5000, соотвественно запрос выберет с 5001-10000 и сделает union с 1-5000 записи — получится список в хронологическом порядке — ему делается reverse().
Записи в словаре хранятся не в порядке вставки.

А>Но в общем мне понравилось обычное решение с list.Insert(0,...) и list.RemoveAt(1001) его и буду использовать с большой вероятностью

Сдвиг на каждое добавление? Так чем Queue-то не устроил?
Re[8]: Очередь фиксированного размера с вытеснением старых
От: Аноним  
Дата: 18.01.11 21:44
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Аноним, Вы писали:


А>>Здравствуйте, samius, Вы писали:


S>>>Вообще говоря это решение обладает недостатками:

S>>>*) записи не удаляются
А>>так их и не нужно удалять, их всегда ровно 10000. Просто старые перезаписываются новыми а не вставляются/удаляются.
S>С чего бы это они перезаписываются?

ну посмотри алгоритм внимательно там значение currentItem бегает по кругу в пределах 0-9999

        if ( currentItem >= queneCapacity )
        {
           currentItem=0;
        }

        quene[ currentItem ] = new MeasureData( p1, p2, p3 );
        currentItem++;


соотвественно словарь сначала забивается 10000 элементами и больше уже не растет.




S>>>*) записи не упорядоченны и берутся не последние

А>>записи как раз упорядочены по Index в порядке добавления, допустим index текущий = 5000, соотвественно запрос выберет с 5001-10000 и сделает union с 1-5000 записи — получится список в хронологическом порядке — ему делается reverse().
S>Записи в словаре хранятся не в порядке вставки.

Ну вот это засада если так.

А>>Но в общем мне понравилось обычное решение с list.Insert(0,...) и list.RemoveAt(1001) его и буду использовать с большой вероятностью

S>Сдвиг на каждое добавление? Так чем Queue-то не устроил?
Ну я так понял что оно не двигает реально..может там связи обычные — но работает очень шустро. Проверил на 100000 записей что в 10 раз больше чем мне нужно — задержка всего 90 микросекунд.
Re[4]: Очередь фиксированного размера с вытеснением старых
От: Аноним  
Дата: 18.01.11 21:50
Оценка:
D>>>Не совсем понятно, почему не подходит обыкновенный List<>?

А>>Вот блин. Оказывается он ничуть не тормозной

А>>Вполне шустро работает. Меньше миллисекунды..196 тиков всего.
А>>А он не двигает все элементы при удаленни чтоли ?
S>Двигает. А Queue — нет.

Ну даже если и двигает то очень быстро..намного быстрее чем я ожидал.
Quene недостаток в получении "перевернутого списка" , с list переворачивать не придется
и все решение сводится для вставки
list.Insert(0, .. );
if ( list.Count > Capacity )
   list.Remove( Capacity );


для получения
/// чтоб копию создать
return list.ToArray();
Re[9]: Очередь фиксированного размера с вытеснением старых
От: samius Япония http://sams-tricks.blogspot.com
Дата: 18.01.11 21:55
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, samius, Вы писали:


S>>Здравствуйте, Аноним, Вы писали:


А>>>Здравствуйте, samius, Вы писали:


S>>С чего бы это они перезаписываются?


А>ну посмотри алгоритм внимательно там значение currentItem бегает по кругу в пределах 0-9999


А>соотвественно словарь сначала забивается 10000 элементами и больше уже не растет.

Да, проглядел

S>>Записи в словаре хранятся не в порядке вставки.


А>Ну вот это засада если так.


А>>>Но в общем мне понравилось обычное решение с list.Insert(0,...) и list.RemoveAt(1001) его и буду использовать с большой вероятностью

S>>Сдвиг на каждое добавление? Так чем Queue-то не устроил?
А>Ну я так понял что оно не двигает реально..может там связи обычные — но работает очень шустро. Проверил на 100000 записей что в 10 раз больше чем мне нужно — задержка всего 90 микросекунд.
Дак двигает реально, без вариантов двигает.
Re[5]: Очередь фиксированного размера с вытеснением старых
От: samius Япония http://sams-tricks.blogspot.com
Дата: 18.01.11 22:01
Оценка:
Здравствуйте, Аноним, Вы писали:

D>>>>Не совсем понятно, почему не подходит обыкновенный List<>?


А>>>Вот блин. Оказывается он ничуть не тормозной

А>>>Вполне шустро работает. Меньше миллисекунды..196 тиков всего.
А>>>А он не двигает все элементы при удаленни чтоли ?
S>>Двигает. А Queue — нет.

А>Ну даже если и двигает то очень быстро..намного быстрее чем я ожидал.

А>Quene недостаток в получении "перевернутого списка" , с list переворачивать не придется
Это лишь вопрос с какой стороны пробегать по результату.

А>и все решение сводится для вставки

А>
А>list.Insert(0, .. );
А>if ( list.Count > Capacity )
А>   list.Remove( Capacity );
А>

С Queue не длиннее

А>для получения

А>
А>/// чтоб копию создать
А>return list.ToArray();
А>

У Queue тоже есть метод ToArray()
Re[4]: Очередь фиксированного размера с вытеснением старых
От: Аноним  
Дата: 18.01.11 22:02
Оценка:
А>>Вполне шустро работает. Меньше миллисекунды..196 тиков всего.
А>>А он не двигает все элементы при удаленни чтоли ?
S>Двигает. А Queue — нет.

вот кстати решил провести тест, получилось

Quene Time:00:00:03.3552024
List Time:00:00:00.5903732

т.е. с Quene в 6 раз медленнее из-за необходимости Reverse()

если Reverse() убрать то получается чуть быстрее листа

Quene Time:00:00:00.3937243
List Time:00:00:00.5932789

    class Program
    {


        static void TestQuene()
        {
            var quene = new Queue<int>();
            int cnt = 0;

            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            for (int i = 0; i < 30000; i++)
            {
                quene.Enqueue(i);
                if (quene.Count > 10000)
                    quene.Dequeue();

                cnt += quene.ToArray().Reverse().Count();
            }

            sw.Stop();

            Console.WriteLine(cnt);
            Console.WriteLine("Quene Time:" + sw.Elapsed);

        }

        static void TestList()
        {
            var quene = new List<int>();
            int cnt = 0;

            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            for (int i = 0; i < 30000; i++)
            {
                quene.Insert(0, 99999999);
                if (quene.Count > 10000)
                    quene.RemoveAt(10000);

                cnt += quene.ToArray().Count();
            }

            sw.Stop();

            Console.WriteLine(cnt);
            Console.WriteLine("List Time:" + sw.Elapsed);

        }


        static void Main(string[] args)
        {
            TestQuene();
            TestList();
            Console.ReadKey();
        }
    }
Re[5]: Очередь фиксированного размера с вытеснением старых
От: samius Япония http://sams-tricks.blogspot.com
Дата: 18.01.11 22:19
Оценка: :)
Здравствуйте, Аноним, Вы писали:

А>>>Вполне шустро работает. Меньше миллисекунды..196 тиков всего.

А>>>А он не двигает все элементы при удаленни чтоли ?
S>>Двигает. А Queue — нет.

А>вот кстати решил провести тест, получилось


А>Quene Time:00:00:03.3552024

А>List Time:00:00:00.5903732

А>т.е. с Quene в 6 раз медленнее из-за необходимости Reverse()


А>если Reverse() убрать то получается чуть быстрее листа


А>Quene Time:00:00:00.3937243

А>List Time:00:00:00.5932789

А>
А>                cnt += quene.ToArray().Reverse().Count();
А>


Так работает вровень, а то и быстрее:
var array = quene.ToArray();
Array.Reverse(array);
cnt += array.Count();

250005000
Quene Time:00:00:00.6969832
250005000
List Time:00:00:00.7490250


P.S. А почему Quene через N?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.