Can C# Ever Match C++ for Speed?

shutterstock_244148398

Can C# beat out C++ for speed of execution? If you asked me that question, I’d generally say “No.” But interested in testing the idea out, I recently took a program written in C++, converted it to C#, and compared the two. The C# version ran twice as fast—something I wasn’t expecting.

Before we plunge into the details of the program, let’s ask if there are areas in which C# will out-speed its competition in this instance. Recent upgrades and feature additions have made C++ a more powerful platform. In past iterations, for example, C++ featured no move semantics, classes had copy constructors, and temporary objects were copies; with C++ 11, classes gained move constructors and move assignment functions, making the language more efficient if you use move semantics. When it comes to strings, C++ also has an advantage, in that C++ chars are 8-bit, whereas C# uses UTF-16 chars that are twice as large.

But there’s also no reason why C# (or other platforms such as Java Virtual Machine, for that matter) can’t be faster than C++ with the right optimizations.

Poker Evaluation

I had written a program in C++ 11 to demonstrate std::async. It did so by evaluating a five-card poker hand to see whether it was decent (i.e., anything from pairs up to a royal flush). I’d previously created a text file with one million poker hands generated randomly, with each card defined as two characters (such as AS for Ace of Spades, TD is ten of diamonds, etc). The code read each hand from the file, 10 characters per line, and wrote another text file with the result of each evaluation; it took 3.5 seconds to do all million.

Ironically, the asynchronous version that used std::async (and std::future) took 20 percent longer to run, presumably because the extra overhead of fetching the future value was significant compared to the evaluation time. By adding a one-millisecond delay and processing 20,000 cards, it took 35 seconds single-threaded but only 3.5 seconds asynchronous. The code below creates a PokerHand object from the string str that’s captured as a parameter by the Lambda expression. MaxThreads is a constant defined as 12 for my computer, which is a six core with hyper-threading. (If you want to full C++ code for this, it’s hosted on GitHub.)

[csharp]
std::array<std::future<std::string>,MaxThreads-1> futures;

auto count = 0;

while (count <MaxThreads-1) {

if (filein.eof()) break;

std::getline(filein, str);

rowCount++;

futures[count++] = std::async([str]{

PokerHand pokerhand(str);

auto result = EvaluateHand(pokerhand);

return pokerhand.GetResult(result);

});

if (count == MaxThreads-1) {

for (auto & e : futures) {

fileout << e.get() << std::endl;

}

count = 0;

}

}

[/csharp]

Note that the synchronous version does this simple loop below; a compiler directive, Multi, selects which version is built:

[csharp]
while (std::getline(filein, str))

{

PokerHand pokerhand(str);

auto result = pokerhand.EvaluateHand();

pokerhand.WriteResult(fileout, result);

rowCount++;

}

[/csharp]

I translated the code more or less line-for-line into C#, and, to my surprise, it only took 1.7 seconds to run. That’s twice as fast on the same hardware and not using async. So either I’m rubbish at writing C++ (quite possibly!) or there’s another explanation. In order to save my C++ reputation, I decided to investigate, looking first at file I/O.

Each time round the loop, both versions created an instance of the PokerHand class, then called the EvaluateHand() method. I commented out the bulk of the code from rowCount++ on down to the last brace and added this line immediately after the std::getline line:

[csharp]
fileout << str << std::endl;
[/csharp]

So now it’s just a simple “read from the in stream” then “write to the out stream,” inside a loop. Running the C++ version took 2.39 seconds for all million rows. When I did the same using the StreamReader() and StreamWriter() classes in C#, it took just 0.11 seconds, over twenty times faster. Clearly the Windows stream I/O classes std::ifstream and std::ofstream are quite slow in comparison to those .NET stream classes. This is the C# code below:

[csharp]
var stw = new Stopwatch();

stw.Start();

using (var sw = new StreamWriter(@"results.txt"))

{

using (var sr = new StreamReader(@"cards.txt"))

{

while (!sr.EndOfStream)

{

var str = sr.ReadLine();

sw.WriteLine(str);

}

sr.Close();

sw.Close();

}

}

stw.Stop();

Console.WriteLine(@"Took {0:0.00} seconds", stw.ElapsedMilliseconds / 1000.0);

[/csharp]

Deducting those times from processing means the rest of the C++ code took (3.5 – 2.39) = 1.11 seconds and the C# version took 1.7 – 0.11 = 1.59 seconds. So now the C++ code was clearly executing faster.

To investigate further, I reverted the code, then commented out the calls to EvaluateHand() in both versions, instead assigning the HighCard enum value. After subtracting the difference between those times, I found that it was only taking 0.08 seconds for the million C++ EvaluateHand() calls and 0.17 for the C# version. That’s fast enough to do 12,500,000 evaluations per second in C++ and about 6 million in C#.

Conclusion

This was an empirical comparison, rather than timing specific instructions, which I was initially tempted to do.

It’s quite surprising that there is a 20 x difference in the streaming performance. While C# code is unlikely to outperform the same C++ code, in some scenarios it can be very fast. For example, I recently wrote a C# utility to do a frequency analysis, counting how many times every word occurred in a 46 MB text file—it took just five seconds on an older PC.

Image Credit: jannoon028/Shutterstock.com

Comments

17 Responses to “Can C# Ever Match C++ for Speed?”

December 10, 2015 at 4:13 am, Elmer said:

If you try deleting say a thousand files in a folder from Windows Explorer, it will take several minutes for Explorer just to calculate how big each file is and what the total will be and then display the confirmation dialog. If you go to terminal and type *.*, it will be over in no time. It all depends on how many libraries need to be loaded to memory and subroutines need to be executed.

Reply

December 10, 2015 at 4:28 am, Mario Rugiero said:

While I find those results surprising, and they are indeed possible, there is still an unexplored case. Maybe the streams in C# aren’t being flushed in every iteration, while std::endl flushes the buffers. Could you try replacing the std::endl by ‘\n’ instead and telling us how this affected your benchmarks?

Reply

December 10, 2015 at 4:49 am, Alexandre Pia said:

In the C++ code, std::endl forces a flush, whereas in C# Console.WriteLine does not.
Try replacing std::endl with “\n”.

Reply

December 10, 2015 at 7:08 am, CodeAngry said:

If you factor in turnaround time, C# becomes a lot more appealing than C++, especially when it comes to utilities/tools that are not performance critical but are complicated enough (e.g.: require some UI) to make writing them in C++ a ‘bit’ slower.

PS: Can’t believe I just said that.

Reply

December 10, 2015 at 7:27 am, Jesse Good said:

Your evaluation that C++ iostreams are slow is a well known fact in the C++ world. Just google for “why is c++ io so slow”, you will find plenty of hits and hints on how to make it faster.

Also a quick look at the C++ code reveals some issues, for example:
1. You seem to be passing std::string by value everywhere even though you never modify it, i.e. PokerCard(std::string cardtext)
2. You are flushing the buffer every time you call “std::endl”. <— Please rerun the benchmark with this improvement, I expect to see a significant gain in performance
3. Stuff like "return ToString() + " " + ValueStr[(int)handvalue];" creates a handful of temporaries.

Reply

December 10, 2015 at 8:41 am, codeJunkie said:

C# is an entry level language, C/C++ is for the coder who wants to dig into the details run their code closer to, if not on, the metal. Any language that uses a built in garbage collector will never beat a language like C/C++ period.

Reply

December 10, 2015 at 9:34 am, Alex Shvedov said:

A pro po: sure way to make C++ _slower_ than C# (or any managed code, for that matter) is to make dtors/finalizers as slow as possible. GC _postpones_ actual destruction to some later time while honest C++ always destructs synchronously.

Say, you have a scope that creates 5 empty (= as simple as possible) managed objects with 1 second finalizers – the scope executes in no time (GC will do the clean-up later); do the same in C++ and the scope will take 5 seconds to execute, all spent in dtors, of course.

Reply

December 10, 2015 at 9:45 am, ctxnop said:

I can’t test right now but I’m pretty sure it’s all because you are “rubbish at writing C++”.
There are multiple reason for your C++ code to be slower :
1) std::getline is slow, it’s wellknown. You shouldn’t use it to read your file. Especially when your file can read “binary” such as when all your line are same lenght.
2) Memory Mapped File are the way to go most of the time.
3) Don’t write std::endl in a loop, it flush the buffer each time, prefer to write “\n”, and manually flush when done.
4) There is a “sync” between C and C++ API which slow down a lot of things, you should disable that lock (http://www.cplusplus.com/reference/ios/ios_base/sync_with_stdio/)
5) When using stream compiler matter A LOT. I wrote a dna matching soft some times ago, and the very same code, on the very same datas, on the very same machine, took 20s when compiled by clang or gcc, but took 19 MINUTES using MSVC12. I found some define to declare in order to gain speed and then it took 1min20s. So it incredibly depend on the flags and macros you use and the compiler (even the same compiler but different version can lead to extreme differences).
6) VM can do things you can too but you won’t think about it. For exemple, VM often try to load the complete file in memory before starting to reading it. Your code didn’t do that, it’s the VM. But in C++, there is no VM to do things like this. If you want to load the complete file before reading, it’s all yours.

So you can only conclude that an unexperienced C# developper will probably write a faster code than an unexperienced C++ developper without even trying to do so.
Which is a great thing after all, because it mean it’s much more easier to write fairely fast code in C# than C++.

Reply

December 10, 2015 at 10:10 am, Patrick said:

I think C# will always be ‘faster’ when comparing full application development. It is simply easier and more productive to develop in. However if we wanted raw speed we could always go straight to assembly.

Even C++ today is a huge leap away from assembly. Most C++ programs could be significantly faster if written in assembly. However who would want to.

Reply

December 10, 2015 at 2:50 pm, Chris_Reno said:

One should not forget that in C# you call also declare a function unsafe and then access pointers and pointer arithmetic just like C++. This can make manipulating arrays, images, and other memory based data structures an order of magnitude faster than the equivalent managed code. Performance should then be on par with the best C++ anytime.

Reply

December 10, 2015 at 3:02 pm, Raja said:

C# all the way. C++ had its time (certainly made a huge impact in our lives) but when I read about C++ 11 features I think it is trying to play catch up with more modern languages. Language is not the only way to improve performance. When things get outdated so quickly I would rather spend 6 months to develop a project in C#, ship the product and make an impact than spending few years trying to do the same in C++. I convinced a computer maker to use C# to speed up development and only use C for boot time modules, of course using C++ compilers (because our computer’s boot time gets reviewed against competitors). They were very happy with the outcome. Most people don’t realize it is the C of C++ that matters most not the OOP part of it that helps, for OOP there are better languages. Developing anything in assembly and mixing it with C++ or C# is non-sense. Assembly should reside in prepackaged stuffs (like drivers, BIOS etc…) to which we interact with using well defined interface.

Reply

December 11, 2015 at 5:22 am, Steffen said:

I made several experiences comparing c#-performance (which I mostly work in) and c++ performance.

1. Observation 1: Writing an application to gather some statistics on disk space usage (breaking it down by folders and files):
a) c++ using Win32-Api: blazing fast, ca. 5s to scan my whole disk
b) c# using FileInfo: 10 minutes

2. Observation 2: Core loop of a C#-Optimization-Application which has to compute a lot of dotproducts (where the bulk of the vectors on one side of the dotproduct are the same over all loops)
a) C++ (C++/Cli-bridge, actual computation in native c++) => fast – whole optimization app 1 minute
b) standard c#: slow: whole optimization app: 10 minutes
c) implementing the dot-product part in c# using ugly unsafe pointer arithmetic: 1 minute – as fast as c++

3. Another medium complex optimization program. Beside negliable startup no external dependencies – all self written discrete optimization with some floating point operations, comparing a huge set of possibilities:
a) C# => fast: 10 min
b) very supprisingly: my machine runs win7. starting up a vm with windows xp and running the program inside the vm => 8 min (faster than in the original machine!!!)
b) c++ (mostly one-to-one port of c# with some consideration regarding avoiding moves):
b1) MSVC: extremely slow – over 90 min
b2) gcc: 15 min (slower than c# but in the same leage – way faster than msvc)

I write professional c# for 15 years now, but only very rarely c++ for hobby – so maybe I am implicitely using a style which works well on c# and bad on c++, but this really supprised me, how slow c++ is here.
I observed something similar some years ago using a java optimization program (again – all the time trying many possibilities without I/o or external calls):
It was way faster running it in the jvm, than using the java-to-native compiler of gcc and then running it – the native version also was factor 10 slower.

Reply

December 11, 2015 at 5:58 am, GeorgeM said:

I agree with your statements about C#. It executes fast, only startup might a bit slower, but now MS is working hard on, and soon releasing, .NET Native, making able to compile your C# developments to a “native” package, without the need for a .NET runtime, hugely increasing startup times, and also some memory-intensive tasks. On top of this it will bring more and more ‘cross-platform’ options, so you only write once (or 90% once), and have it compiled for every popular platform at max performance.
So, if only from a business perpective, this would be the obvious choice to make. And Apple KNOWS this, and that’s why they’ve open-source Swift last week + making it able to run on Linux now, and in the future also do cross-platform builds. And they refer to Microsoft for this change of plans. They know that this is the future…follow or become irrelevant.
I don’t agree with the assembler stuff though…there are quite some examples of products that benefit from using assembler-parts in the code, be it C++ or C# applications. For example process-heavy image-effects or music effects, so DSP, are mostly done in assembler because, especially for music, near-zero response times are required, so assembly really is a necessity here.

Reply

December 11, 2015 at 11:37 am, Oscar2 said:

@codeJunkie: you say that “a garbage collected language can never beat C++ period”. I think you ignore something very important about languages like C# and Java. Because they generate byte codes for a virtual machine, and because the VM optimizes the runtime code IN REAL-TIME, they can optimize for actual runtime performance. I have written several programs in Java that run circles around the same program in C or C++.
One was a large neural network application, I could not make the C version keep up with the Java version just because the real-time Java optimizer was so much better than anything that could be done by the static compile time C optimizer.

Reply

December 14, 2015 at 2:12 pm, nikau said:

The only thing I learned by reading your code is that you do not know C++. Your C++ code is rubish. Nobody will never hired you to write C++ code.

Reply

December 18, 2015 at 8:41 am, ReVeLaTeD said:

I disagree that “C++ has had its time” as Raja posits.

codeJunkie refers to running “on the metal”. I can’t emphasize enough why this is critical for certain applications. Like Content Management – specifically, scanning and working with large file formats – video transcoding and encoding, CAD, basic OCR, full text indexing, zonal indexing, and other intensive applications.

I know the buzzword of the year is “cloud”. I know the hype thing to do is throw everything into a VM shared with 400 other apps in order to save some money. But orgs that care about performance and outcomes will not compromise on a web-based utility to do any of the above for their needs. Yes, I know some vendors have web-based utilities. They are childish compared to a locally installed, C++ compiled .exe on a beast spec physical machine.

Reply

August 23, 2016 at 12:05 pm, Bob said:

I mostly do data analysis that doesn’t require super computing performance.. I’ve written a few c# apps and the performance has been impressive. So why waste precious time writing c++? C# is a nice speedy alternative thats productive and clean, so you won’t have to use slow as mud python.

Reply

Post a Comment

Your email address will not be published.