Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Alex Warm Россия  
Дата: 19.12.13 08:28
Оценка:
Добрый день.

Нужно подсчитать количество одинаковых байтов. Самый простой способ выглядит так.
        public int[] stat(byte[] data)
        {
            int[] result = new int[256];
            for (int i = 0; i < stat.Length; i++)
            {
                result[data[i]]++;
            }
            return result;
        }


Есть ли более быстрые способы?
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Re: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Alex Warm Россия  
Дата: 19.12.13 08:32
Оценка:
AW> for (int i = 0; i < data.Length; i++)

Извиняюсь, обшибся в имени массива
Re: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: LaptevVV Россия  
Дата: 19.12.13 08:33
Оценка:
Здравствуйте, Alex Warm, Вы писали:
AW>Есть ли более быстрые способы?
Быстрее линейного — нет.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: dotidot Россия  
Дата: 19.12.13 08:47
Оценка: +1 :)
Здравствуйте, AAW

AW>Есть ли более быстрые способы?


можно расппареллить, простенькая задачка на fork join
Re[2]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Alex Warm Россия  
Дата: 19.12.13 08:55
Оценка:
Здравствуйте, dotidot, Вы писали:
AW>>Есть ли более быстрые способы?
D>можно расппареллить, простенькая задачка на fork join

Можно пример или ссылку?
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Re[3]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: dotidot Россия  
Дата: 19.12.13 09:55
Оценка:
Здравствуйте, Alex Warm, Вы писали:

AW>Можно пример или ссылку?

ну это совсем hello world
если совсем по простому — разбить массив на N частей (например на 8) и посчитать количество разных байт в каждой части параллельно, потом результаты сложить
Re[4]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Alex Warm Россия  
Дата: 19.12.13 10:11
Оценка:
Здравствуйте, dotidot, Вы писали:
AW>>Можно пример или ссылку?
D>ну это совсем hello world
D>если совсем по простому — разбить массив на N частей (например на 8) и посчитать количество разных байт в каждой части параллельно, потом результаты сложить

блин. я думал что-то связанное с Paralell...
OK. Всем спасибо за помощь.
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Re[3]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Yoriсk  
Дата: 19.12.13 10:24
Оценка: -2
Здравствуйте, Alex Warm, Вы писали:

AW>Можно пример или ссылку?


Ну "в лоб" как-то так:

Parallel.For(0, data.Length, i => Interlocked.Increment(ref result[data[i]]));
Re[4]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Alex Warm Россия  
Дата: 19.12.13 10:36
Оценка:
Здравствуйте, Yoriсk, Вы писали:

AW>>Можно пример или ссылку?

Y>Ну "в лоб" как-то так:
Y>
Parallel.For(0, data.Length, i => Interlocked.Increment(ref result[data[i]]));


Увы, результат не порадовал.
при первом вызове 90мс, против 9 в изначальном примере.
при повторных вызовах падает до 14, но все равно много.
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Re[5]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Yoriсk  
Дата: 19.12.13 12:01
Оценка:
Здравствуйте, Alex Warm, Вы писали:

AW>Увы, результат не порадовал.


Да, действительно. У меня самым быстрым получился вариант с побить его на части и паралельно уже запускать ваш stat(даже с учётом копирования в новые массивы быстрее в ~2 разa чем у ТС).
Только копировать надо blockcopy, а то linq весь выигрыш съедает.
Re[5]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Sinix  
Дата: 19.12.13 13:08
Оценка: 3 (1)
Здравствуйте, Alex Warm, Вы писали:

AW>при повторных вызовах падает до 14, но все равно много.

Разумеется, потому что нефиг пытаться распараллелить код, выполняющийся миллисекунды, особенно если каждая итерация стоит копейки. Максимум, что вы выиграете — разы, да и то c трудом:
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace VS2013Compatibility
{
    class Program
    {
        static void Main(string[] args)
        {
            var rnd = new Random(0);
            const int ByteCount = 100 * 1024 * 1024;
            var data = new byte[ByteCount];
            rnd.NextBytes(data);

            Measure("Simple", () =>
            {
                int[] result = new int[256];
                for (int i = 0; i < data.Length; i++)
                {
                    result[data[i]]++;
                }
                return result.Max() + result[0];
            });

            Measure("Parallel For", () =>
            {
                var result = new int[256];
                var rangePartitioner = Partitioner.Create(0, data.Length);
                
                Parallel.ForEach(
                    rangePartitioner,
                    () => new int[256],
                    (t, st, res) =>
                    {
                        for (int i = t.Item1; i < t.Item2; i++)
                        {
                            res[data[i]]++;
                        }
                        return res;
                    },
                    res =>
                    {
                        lock (data)
                        {
                            for (int i = 0; i < res.Length; i++)
                            {
                                result[i] += res[i];
                            }
                        }
                    });

                return result.Max() + result[0];
            });

            Console.WriteLine("Done.");
            Console.ReadKey();
        }

        static void Measure<T>(string name, Func<T> callback)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            var sw = Stopwatch.StartNew();
            var tmp = callback();
            sw.Stop();

            Console.WriteLine("{0,20}: {1,5}ms : {2,9}", name, sw.ElapsedMilliseconds, tmp);
        }
    }
}



// 4.5.1, x86
              Simple:   139ms :    820658
        Parallel For:    56ms :    820658
Done.

// x4.5.1, x64
              Simple:    71ms :    820658
        Parallel For:    88ms :    820658
Done.
Re: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Аноним  
Дата: 19.12.13 18:23
Оценка:
Здравствуйте, Alex Warm, Вы писали:

AW>Нужно подсчитать количество одинаковых байтов.

AW>Есть ли более быстрые способы?

отсортировать и выдать длинну каждой цепочки
Re[2]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Draqon  
Дата: 19.12.13 18:37
Оценка:
И все это быстрее чем за линейное время?! Код не покажете?

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

А>отсортировать и выдать длинну каждой цепочки
Re[2]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Regular_Man  
Дата: 19.12.13 18:41
Оценка:
Здравствуйте, Аноним, Вы писали:

А>отсортировать и выдать длинну каждой цепочки


Это не будет быстрее. Сортировка имеет nlog n сложность. Это хуже чем линейный алгоритм.
Re[2]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Regular_Man  
Дата: 19.12.13 19:09
Оценка: +1
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, Alex Warm, Вы писали:

AW>>Есть ли более быстрые способы?
LVV>Быстрее линейного — нет.

Абсолютно согласен, быстрее нет. Ускорить конкретный код можно только если задействовать аппаратные возможности MMX, SSE и т.п. Либо воспользоваться готовыми реализациями, например, из OpenCV.
Re[6]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Sergey_BG Россия  
Дата: 20.12.13 20:39
Оценка:
Здравствуйте, Sinix, Вы писали:

S> Parallel.ForEach(

S> rangePartitioner,
S> () => new int[256],
S> (t, st, res) =>
S> {
S> for (int i = t.Item1; i < t.Item2; i++)
S> {
S> res[data[i]]++;
S> }
S> return res;
S> },
S> res =>
S> {
S> lock (data)
S> {
S> for (int i = 0; i < res.Length; i++)
S> {
S> result[i] += res[i];
S> }
S> }
S> });

Как я понимаю, здесь вызывается следующий метод класса Parallel:
ForEach<TSource, TLocal>(OrderablePartitioner<TSource>, Func<TLocal>, Func<TSource, ParallelLoopState, Int64, TLocal, TLocal>, Action<TLocal>)

Но мне не понятно как лямбда с тремя параметрами
(t, st, res) =>
{
        for (int i = t.Item1; i < t.Item2; i++)
    {
        res[data[i]]++;
    }
    return res;
},

используется вместо Func<TSource, ParallelLoopState, Int64, TLocal, TLocal>.

Или же здесь используется ForEach<TSource, TLocal>(IEnumerable<TSource>, ParallelOptions, Func<TLocal>, Func<TSource, ParallelLoopState, TLocal, TLocal>, Action<TLocal>) ?
Но OrderablePartitioner<TSource> не поддерживает IEnumerable<TSource>.
Сергей
Re[6]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Философ Ад http://vk.com/id10256428
Дата: 20.12.13 21:05
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, Alex Warm, Вы писали:


AW>>при повторных вызовах падает до 14, но все равно много.

S>Разумеется, потому что нефиг пытаться распараллелить код, выполняющийся миллисекунды, особенно если каждая итерация стоит копейки. Максимум, что вы выиграете — разы

Если ты делаешь графические эффекты, то миллисекунды иногда оказываются недопустимой роскошью.
Разы — очень хороший выигрыш.
Всё сказанное выше — личное мнение, если не указано обратное.
Re[7]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Sinix  
Дата: 23.12.13 05:38
Оценка:
Здравствуйте, Sergey_BG, Вы писали:

S_B>Как я понимаю, здесь вызывается следующий метод класса Parallel:

S_B>ForEach<TSource, TLocal>(OrderablePartitioner<TSource>, Func<TLocal>, Func<TSource, ParallelLoopState, Int64, TLocal, TLocal>, Action<TLocal>)

Вот этот:
public static ParallelLoopResult ForEach<TSource, TLocal>(
    Partitioner<TSource> source,
    Func<TLocal> localInit,
    Func<TSource, ParallelLoopState, TLocal, TLocal> body,
    Action<TLocal> localFinally
)

Re[7]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Sinix  
Дата: 23.12.13 05:54
Оценка:
Здравствуйте, Философ, Вы писали:

AW>>>при повторных вызовах падает до 14, но все равно много.

S>>Разумеется, потому что нефиг пытаться распараллелить код, выполняющийся миллисекунды, особенно если каждая итерация стоит копейки. Максимум, что вы выиграете — разы

Ф>Если ты делаешь графические эффекты, то миллисекунды иногда оказываются недопустимой роскошью.

Ф>Разы — очень хороший выигрыш.
За счёт распараллеливания на cpu экономить миллисекунды выиграть практически нет. Накладные расходы на переключение контекста будут сопоставимы с выигрышем. Единственное, что мы точно увеличим — энергопотребление.
И да, как задача топикстартера соотносится с графическими эффектами?
Re[8]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
От: Философ Ад http://vk.com/id10256428
Дата: 23.12.13 07:59
Оценка:
Здравствуйте, Sinix, Вы писали:

S>За счёт распараллеливания на cpu экономить миллисекунды выиграть практически нет. Накладные расходы на переключение контекста будут сопоставимы с выигрышем. Единственное, что мы точно увеличим — энергопотребление.


Не всегда нужно контекст переключать. Для некоторых подходов синхронизация не нужна, например при распараллеливании на уровне данных (здесь это — loop distribution), это приводит к тому что переключение контекстов минимально.

Переключение контекста — микросекундная операция.
Мои эксперименты показали, что в Win2k3 на Core 2 функции WaitForSingleObject() и SetEvent() в среднем возвращаются через 1600 — 2500 тактов, в зависимости от фазы луны. Ясен пень, что для функции ожидания такие значения для изначально сигнального состояния event'а. Характерные тактовые частоты C2D >= 2 GHz, следовательно время задержки 1.0/2.0E09 * 2E03 = 1.0E-06 (одна микросекунда).
Т.е. при минимизации переключений контекста и времени ожидания, распараллеливание миллисекундных операций имеет смысл, особенно если потоки создать заранее.


S>И да, как задача топикстартера соотносится с графическими эффектами?


Я не знаю какая именно у него задача.
Всё сказанное выше — личное мнение, если не указано обратное.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.