Здравствуйте, Alex Warm, Вы писали:
AW>Можно пример или ссылку?
ну это совсем hello world
если совсем по простому — разбить массив на N частей (например на 8) и посчитать количество разных байт в каждой части параллельно, потом результаты сложить
Re[4]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
Здравствуйте, dotidot, Вы писали: AW>>Можно пример или ссылку? D>ну это совсем hello world D>если совсем по простому — разбить массив на N частей (например на 8) и посчитать количество разных байт в каждой части параллельно, потом результаты сложить
блин. я думал что-то связанное с Paralell...
OK. Всем спасибо за помощь.
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Re[3]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
Здравствуйте, Alex Warm, Вы писали:
AW>Увы, результат не порадовал.
Да, действительно. У меня самым быстрым получился вариант с побить его на части и паралельно уже запускать ваш stat(даже с учётом копирования в новые массивы быстрее в ~2 разa чем у ТС).
Только копировать надо blockcopy, а то linq весь выигрыш съедает.
Re[5]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
Здравствуйте, 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);
}
}
}
Здравствуйте, LaptevVV, Вы писали:
LVV>Здравствуйте, Alex Warm, Вы писали: AW>>Есть ли более быстрые способы? LVV>Быстрее линейного — нет.
Абсолютно согласен, быстрее нет. Ускорить конкретный код можно только если задействовать аппаратные возможности MMX, SSE и т.п. Либо воспользоваться готовыми реализациями, например, из OpenCV.
Re[6]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
Здравствуйте, 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[]. Если метод быстрее?
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Alex Warm, Вы писали:
AW>>при повторных вызовах падает до 14, но все равно много. S>Разумеется, потому что нефиг пытаться распараллелить код, выполняющийся миллисекунды, особенно если каждая итерация стоит копейки. Максимум, что вы выиграете — разы
Если ты делаешь графические эффекты, то миллисекунды иногда оказываются недопустимой роскошью.
Разы — очень хороший выигрыш.
Всё сказанное выше — личное мнение, если не указано обратное.
Re[7]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
Здравствуйте, Sergey_BG, Вы писали:
S_B>Как я понимаю, здесь вызывается следующий метод класса Parallel: S_B>ForEach<TSource, TLocal>(OrderablePartitioner<TSource>, Func<TLocal>, Func<TSource, ParallelLoopState, Int64, TLocal, TLocal>, Action<TLocal>)
Здравствуйте, Философ, Вы писали:
AW>>>при повторных вызовах падает до 14, но все равно много. S>>Разумеется, потому что нефиг пытаться распараллелить код, выполняющийся миллисекунды, особенно если каждая итерация стоит копейки. Максимум, что вы выиграете — разы
Ф>Если ты делаешь графические эффекты, то миллисекунды иногда оказываются недопустимой роскошью. Ф>Разы — очень хороший выигрыш.
За счёт распараллеливания на cpu экономить миллисекунды выиграть практически нет. Накладные расходы на переключение контекста будут сопоставимы с выигрышем. Единственное, что мы точно увеличим — энергопотребление.
И да, как задача топикстартера соотносится с графическими эффектами?
Re[8]: Подсчет количества повторяющихся элементов в byte[]. Если метод быстрее?
Здравствуйте, 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>И да, как задача топикстартера соотносится с графическими эффектами?
Я не знаю какая именно у него задача.
Всё сказанное выше — личное мнение, если не указано обратное.