Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Simple loop
Time: 00:00:07.6342930
Delta: -4,13447054370408E-13
ParallelEnumerable
Time: 00:00:01.8987034
Delta: -1,12732045920438E-12
Parallel.For
Time: 00:00:01.3737671
Delta: -3,9552361386086E-11
Parallel.ForEach
Time: 00:00:01.0942734
Delta: -9,59232693276135E-13
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace TempConsoleApplication {
public static class Program {
private const double Result = 1.2502304241756868163500362795713040947699040278200;
private const int IterCount = 200000000;
private static void Main(string[] args) {
Start("Simple loop", n => {
double sum = 0.0;
for (double i = 1.0; i <= n; ++i) {
sum += Math.Sin(i);
}
return sum;
});
Start("ParallelEnumerable",
n => ParallelEnumerable.Range(1, n).Select(i => Math.Sin(i)).Sum());
Start("Parallel.For", n => {
var sum = 0.0;
Parallel.For(
1,
n + 1,
() => 0.0,
(i, state, sumL) => Math.Sin(i) + sumL,
sumL => Sum(ref sum, sumL));
return sum;
});
Start("Parallel.ForEach", n => {
var sum = 0.0;
Parallel.ForEach(
Partitioner.Create(1, n + 1),
() => 0.0,
(range, state, sumL) => {
for (int i = range.Item1; i < range.Item2; ++i) {
sumL += Math.Sin(i);
}
return sumL;
},
sumL => Sum(ref sum, sumL));
return sum;
});
Console.ReadKey();
}
private static void Sum(ref double sum, double sumL) {
double initial, computed;
do {
initial = sum;
computed = initial + sumL;
}
while (initial != Interlocked.CompareExchange(ref sum, computed, initial));
}
private static void Start(string name, Func<int, double> func) {
func(100);
var s = Stopwatch.StartNew();
var sum = func(IterCount);
s.Stop();
Console.WriteLine(name);
Console.WriteLine("Time: " + s.Elapsed);
Console.WriteLine("Delta: " + (sum - Result));
Console.WriteLine();
}
}
}
2x8 физических ядер с гипертредингом
#pragma omp parallel for reduction (+ : res)
for (int i = 1; i <= 200000000; i++)
res+=sin(i);

let threadCount = 6
let serialSum first last =
let mutable res = 0.0
for i=first to last do
res <- res + sin(float i)
res
let parallelSum first last =
let count = last - first + 1
let perThreadCount = count / threadCount + (if count % threadCount = 0 then 0 else 1)
seq {
for i=0 to threadCount - 1 do
let localFirst = first + (perThreadCount * i)
let localLast = min last (localFirst + perThreadCount - 1)
yield async { return serialSum localFirst localLast }
}
|> Async.Parallel
|> Async.RunSynchronously
|> Array.sum
#time
> serialSum 1 200000000;;
Real: 00:00:06.930, CPU: 00:00:06.926, GC gen0: 0, gen1: 0, gen2: 0
val it : float = 1.250230424
> parallelSum 1 200000000;;
Real: 00:00:01.331, CPU: 00:00:07.644, GC gen0: 0, gen1: 0, gen2: 0
val it : float = 1.250230424
#include <iostream>
#include <math.h>
#include <sys/time.h>
using namespace std;
unsigned long int time_delta(struct timeval *from, struct timeval *to) {
unsigned long int delta = to->tv_sec * 1000000l + to->tv_usec;
return delta - (from->tv_sec * 1000000l + from->tv_usec);
}
int main()
{
struct timeval start, end;
double res=0.0;
gettimeofday(&start, 0);
for (int i = 1; i <= 200000000; i++)
res+=sin(i);
gettimeofday(&end, 0);
cout.precision(20);
cout << "Result: " << res << " time: " << time_delta(&start, &end)/1000000.0 << "s" << endl;
}


In[1]:= Timing[NSum[Sin[i], {i, 1, 200000000}, WorkingPrecision -> 40]]Первое число в фигурных скобках — затраты машинного времени в секундах, второе — результат с точностью 40 знаков. Использован NSum[] — численное суммирование (стандартный Sum[] посчитает точное значение без округлений).
Out[1]= {0.358, 1.250230424175686816349232062751776829530}
In[1]:= Timing[Sum[Sin[i], {i, 1, 200000000}]]
Out[1]= {0.046, 1/2 (Cot[1/2] — Cos[400000001/2] Csc[1/2])}
Выбор инструмента для расчётов с плавающей точкой — практические советы