65 ms·
It looks like the RealBASIC version was written first and then translated straight into C#. In reality, you'd not create the encoding each time, and either use
by ajanuary 14y ago
It looks like the RealBASIC version was written first and then translated straight into C#.
In reality, you'd not create the encoding each time, and either use a StringBuilder to build up the string, or just use Encoding.GetString.
C# on my machine:
As per blog: 50s
Creating Encoding once: 24s
Using StringBuilder: 11s
Using Encoding.GetString: 2.5s
Use Random.NextBytes: 2s
RealBASIC on my machine:
As per blog: 27s
Interestingly despite advice I'd found on the internet[1] using array joining didn't really make the RealBASIC version any faster, so from what I can tell it's generally as fast as it could be using the out of the box libraries.
(My machine isn't exactly idle and ideal for microbenchmarking atm, but the differences are large enough for that not to matter)
This doesn't really provide a good evaluation on the state of JITs.
[1] http://forums.realsoftware.com/viewtopic.php?f=13&t=25107 http://forums.realsoftware.com/viewtopic.php?f=13&t=2510...
[Edit: Added RealBASIC times]
- gjulianm 14y agoI'm fairly surprised in the results using StringBuilder. I didn't know it was so fast compared with plain concatenation. According to what I've read in MSDN [1], memory allocation has a lot to do with it. I think I'll start using this class in my code. By the way, this leads me to one question: does the code string a = "a" + "b" + "c" + "d"; generate one or three memory allocations (one to compute each concatenation)?
- ajanuary 14y agoBecause you're concatenating literals, the compiler will translate it into string a = "abcd" ;) Strings are outwardly immutable, so concatenating any two strings will create an entirely new String object, along with the memory allocation needed for that. However, there are some internal methods that allow String and other classes in the same corelib assembly (such as StringBuilder) to mutate them. `string a = x + y + z` will be translated into `string a = String.Concat(x, y, z)`. Because it knows the final length it can use the internal String methods to allocate a new String long enough to fit all the arguments and then copy the characters into that without any intermediate representations. [1] In a loop it doesn't know how big the final result will be, and so has to create a new String object on each iteration. If you're doing 16000000 concatenations as in this test that's a lot of intermediate strings that are largely being wasted. StringBuilders have a private String object and use the internal String methods to mutate that when you call Append. When you call ToString it returns a copy of the private String object. Again, this avoids creating lots of new intermediate String objects, but does have the overhead of having to guess how large the initial String should be, and growing it if you append too much (similar to how Lists work). [1] I believe in Java it's translated into using StringBuffer or StringBuilder, which has a small overhead of creating the StringBuffer/StringBuilder object. [Edit: Corrected how String.Concat and StringBuilders work based on the Mono codebase]
- Dykam 14y agoFor others interested in the source of StringBuilder: https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Text/StringBuilder.cs#L50 https://github.com/mono/mono/blob/master/mcs/class/corlib/Sy... Note that the actual magic consists of internal methods in String.cs: - FormatHelper https://github.com/mono/mono/blob/master/mcs/class/corlib/System/String.cs#L1928 https://github.com/mono/mono/blob/master/mcs/class/corlib/Sy... - InternalSetChar https://github.com/mono/mono/blob/master/mcs/class/corlib/System/String.cs#L2585 https://github.com/mono/mono/blob/master/mcs/class/corlib/Sy... - CharCopy https://github.com/mono/mono/blob/master/mcs/class/corlib/System/String.cs#L3060 https://github.com/mono/mono/blob/master/mcs/class/corlib/Sy...