|
|
|
|
|
by privethedge
2419 days ago
|
|
Then why do I have the following results? const a = [...Array(1000000).keys()];
const m = 8;
let leftAvg = .0;
for(let _ of Array(m)) {
const t0 = performance.now();
a.map(Math.tan).map(Math.sin);
const t1 = performance.now();
leftAvg += (t1 - t0)/m;
}
let rightAvg = .0;
for(let _ of Array(m)) {
const t0 = performance.now();
a.map(x => Math.sin(Math.tan(x)));
const t1 = performance.now();
rightAvg += (t1 - t0)/m;
}
console.log(leftAvg, rightAvg, leftAvg/rightAvg);
// JS Firefox 70: 264 360.75 0.7318087318087318
var a = Enumerable.Range(0, 10000000).Select(x => (double)x).ToArray();
double[] xs1 = null;
double[] xs2 = null;
var m = 16;
var leftAvg = .0;
foreach (var _ in Enumerable.Range(0, m))
{
var watch = System.Diagnostics.Stopwatch.StartNew();
xs1 = a.Select(Math.Tan).ToArray().Select(Math.Sin).ToArray();
watch.Stop();
leftAvg += (double)watch.ElapsedMilliseconds / m;
}
var rightAvg = .0;
foreach (var _ in Enumerable.Range(0, m))
{
var watch = System.Diagnostics.Stopwatch.StartNew();
xs2 = a.Select(x => Math.Sin(Math.Tan(x))).ToArray();
watch.Stop();
rightAvg += (double)watch.ElapsedMilliseconds / m;
}
Console.WriteLine($"{leftAvg} {rightAvg} {leftAvg / rightAvg}");
// C# Results: 505.75 602.25 0.839767538397675
|
|
It also matters how this code is compiled exactly. The C# version (I know nothing about C# or how good its compiler is) looks like it must first allocate some kind of dynamic stream, and only when ToArray() is called can it allocate the final array, so there might be extra copying. Maybe the compiler is smart enough to optimize a sequence of arr.Select().ToArray() to allocate a target array of the size of arr right away, I don't know.
Also, the JavaScript version uses a smaller array than the C# version, is that on purpose? 1000000 unboxed doubles are only 8 MB, which is not very big: On the machine I'm typing this on, L3 cache is 6 MB.
My advice would be to run the JavaScript version many times, for many more than 8 iterations, and with sizes increasing stepwise up to a GB or so. Also try replacing the maps with preallocated arrays and hand-written loops that contain only the computations, not the allocations. I know this sounds like I'm trying to give you homework, which I'm not, but benchmarking is hard, and there are many factors to take into account.