On Sunday, 5 February 2017 at 04:22:30 UTC, rikki cattermole
wrote:
On 05/02/2017 5:02 PM, thedeemon wrote:
snip
It may look so from a distance. But in my experience it's not
that bad.
In most software I did in D it did not matter really (it's
either 64-bit
or short lived programs) and the control D gives to choose how
to deal
with everything makes it all quite manageable, I can decide
what to take
from both worlds and hence pick the best, not the worst.
The best of both worlds can be done quite simply.
Instead of a chain of input ranges like:
int[] data = input.filter!"a != 7".map!"a * 2".array;
Use:
int[] data;
data.length = input.length;
size_t i;
foreach(v; input.filter!"a != 7".map!"a * 2") {
data[i] = v;
i++;
}
data.length = i;
Of course this is dirt simple example, but instead look at it
for e.g. a csv parser with some complex data structure creation
+ manipulation.
I have some real world code here[0] that uses it. Not only is
there less allocations and uses the GC but also it ends up
being significantly faster!
[0]
https://gist.github.com/rikkimax/42c3dfa6500155c5e441cbb1437142ea#file-reports-d-L124
Some data to weigh that in order to compare different memory
management strategies on that simple case:
#!/usr/bin/env rdmd
import std.conv;
import std.stdio;
import std.array;
import std.range;
import std.algorithm;
auto input = [1, 2, 7, 3, 7, 8, 8, 9, 7, 1, 0];
void naive() {
int[] data = input.filter!(a => a!= 7).map!(a => a*2).array;
assert(data == [2, 4, 6, 16, 16, 18, 2, 0], data.to!string);
}
void maxReallocs() {
int[] data;
size_t i;
foreach(v ; input.filter!(a => a!=7).map!(a => a*2)) {
data ~= v;
}
assert(data == [2, 4, 6, 16, 16, 18, 2, 0], data.to!string);
}
void betterOfTwoWorlds() {
int[] data;
data.length = input.length;
size_t i;
foreach(v ; input.filter!(a => a!=7).map!(a => a*2)) {
data[i] = v;
i++;
}
data.length = i;
assert(data == [2, 4, 6, 16, 16, 18, 2, 0], data.to!string);
}
void explicitNew() {
int[] data = new int[input.length];
scope(exit) delete data;
size_t i;
foreach(v ; input.filter!(a => a!=7).map!(a => a*2)) {
data[i] = v;
i++;
}
data.length = i;
assert(data == [2, 4, 6, 16, 16, 18, 2, 0], data.to!string);
}
void cStyle() @nogc {
import std.c.stdlib;
int* data = cast(int*)malloc(input.length * int.sizeof);
scope(exit) free(data);
size_t i;
foreach(v ; input.filter!(a => a!=7).map!(a => a*2)) {
data[i++] = v;
}
debug assert(data[0..i] == [2, 4, 6, 16, 16, 18, 2, 0],
data.to!string);
}
void onTheStack() @nogc {
int[100] data;
size_t i;
foreach(v ; input.filter!(a => a!=7).map!(a => a*2)) {
data[i++] = v;
}
debug assert(data[0..i] == [2, 4, 6, 16, 16, 18, 2, 0],
data.to!string);
}
void main(string[] args) {
import std.datetime;
benchmark!(
naive,
maxReallocs,
betterOfTwoWorlds,
explicitNew,
cStyle,
onTheStack
)(100000).each!writeln;
}
/* Results:
Compiled with dmd -profile=gc test.d
====================================
TickDuration(385731143) // naive,
TickDuration(575673615) // maxReallocs,
TickDuration(255928562) // betterOfTwoWorlds,
TickDuration(270497154) // explicitNew,
TickDuration(97596363) // cStyle,
TickDuration(96467459) // onTheStack
GC usage:
bytes allocated, allocations, type, function, file:line
17600000 100000 int[] test.explicitNew test.d:43
4400000 100000 int[] test.betterOfTwoWorlds
test.d:30
3200000 800000 int[] test.maxReallocs test.d:22
3200000 100000 int[] test.maxReallocs test.d:25
3200000 100000 int[] test.explicitNew test.d:51
3200000 100000 int[] test.explicitNew test.d:53
3200000 100000 int[] test.betterOfTwoWorlds
test.d:37
3200000 100000 int[] test.betterOfTwoWorlds
test.d:39
3200000 100000
std.array.Appender!(int[]).Appender.Data
std.array.Appender!(int[]).Appender.this
/usr/include/dlang/dmd/std/array.d:2675
3200000 100000 int[] test.naive test.d:14
Compiled with dmd -O -inline test.d
===================================
TickDuration(159383005) // naive,
TickDuration(187192137) // maxReallocs,
TickDuration(94094585) // betterOfTwoWorlds,
TickDuration(102374657) // explicitNew,
TickDuration(41801695) // cStyle,
TickDuration(45613954) // onTheStack
Compiled with dmd -O -inline -release -boundscheck=off test.d
=============================================================
TickDuration(152151439) // naive,
TickDuration(140870515) // maxReallocs,
TickDuration(46740440) // betterOfTwoWorlds,
TickDuration(59089016) // explicitNew,
TickDuration(26038060) // cStyle,
TickDuration(25984371) // onTheStack
*/