Пример закона Амдаля в С# - программирование
Подтвердить что ты не робот

Пример закона Амдаля в С#

Я работал с некоторой парализацией, и это заставило меня взглянуть на закон Амдала. Я прочитал несколько сообщений по этой теме;

Рассчитайте прирост производительности, используя Закон Амдала

Как рассчитать закон Амадала для эффективности потоков

http://en.wikipedia.org/wiki/Amdahl%27s_law

... но надеялся найти пример С#, демонстрирующий это на практике. Поиск не дал никаких результатов. Теоретически должно быть возможно сделать серийное приложение, время параллелизуемых частей, запустить параллельную версию, записать длину, требуемую параллельными частями, и сравнить разницу (зная, сколько процессоров используется), к результату функции Amdahl. Это правильно и кому-нибудь известно о существующем примере?

4b9b3361

Ответ 1

Примечание. Полную рабочую загружаемую версию программы можно найти на странице My Github.

Итак, с Amdahl Law мы разделили работу на "Работа, которая должна выполняться в последовательном порядке" и "Работа, которая может быть распараллелена", поэтому пусть эти две рабочие нагрузки обозначают как List<Action>:

var serialWorkLoad = new List<Action> { DoHeavyWork, DoHeavyWork };
var parallelizableWorkLoad = new List<Action> { DoHeavyWork, DoHeavyWork, DoHeavyWork, DoHeavyWork, DoHeavyWork, DoHeavyWork, DoHeavyWork, DoHeavyWork };

Где делегат DoHeavyWork абстрагируется отрывочно:

static void DoHeavyWork()
{
    Thread.Sleep(500);
}

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

Затем нам нужно запустить обе рабочие нагрузки в Serial, чтобы получить нашу базовую линию:

var stopwatch = new Stopwatch();
stopwatch.Start();
// Run Serial-only batch of work
foreach (var serialWork in serialWorkLoad)
{
    serialWork();
}

var s1 = stopwatch.ElapsedMilliseconds;

// Run parallelizable batch of work in serial to get our baseline
foreach (var notParallelWork in parallelizableWorkLoad)
{
    notParallelWork();
}

stopwatch.Stop();
var s2 = stopwatch.ElapsedMilliseconds - s1;

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

stopwatch.Reset();
stopwatch.Start();
// Run Serial-only batch of work
foreach (var serialWork in serialWorkLoad)
{
    serialWork();
}

var p1 = stopwatch.ElapsedMilliseconds;

// Run parallelizable batch of work in with as many degrees of parallelism as we can
Parallel.ForEach(parallelizableWorkLoad, (workToDo) => workToDo()); // In Java this is Magic Unicorns

stopwatch.Stop();
var p2 = stopwatch.ElapsedMilliseconds - p1;

Теперь, когда у нас есть базовая линия и параллельная версия, мы можем рассчитать ускорение и сообщить о наших результатах:

var speedup = (double)(s1 + s2) / (p1 + p2);

Console.WriteLine("Serial took  : {2}ms, {0}ms for serial work and {1}ms for parallelizable work", s1, s2, s1 + s2);
Console.WriteLine("Parallel took: {2}ms, {0}ms for serial work and {1}ms for parallelizable work", p1, p2, p1 + p2);
Console.WriteLine("Speedup was {0:F}x", speedup);

И как говорит вам Закон Амдаля, трудно отлично масштабировать С# ядрами, которые у вас есть, из-за работы только для сериализации.