Inspired by this article.There are three opinions regarding the performance of C ++ and C #.
Those who know (or think they know) C ++ believe that C ++ is several times or even orders of magnitude faster.
Those who know C ++ and C # know that for ordinary tasks, C ++ performance is not necessary, and where necessary, it is possible to optimize the C # code as well. The upper limit of optimization for C ++ is higher than that of C #, but nobody needs such records.
Those who know only C # have never experienced problems with its speed.
')
People from the first category all the time trying to prove their case. At the same time, there are examples of optimized C ++ code and the most pessimized C # code.
An example of a "typical" comparison

Any programmer who knows C # will immediately see two errors:
- Calling GC.Collect, which negates any optimizations made in runtime for garbage collection.
- The use of for loop, which is guaranteed not to eliminate the checking of boundaries for each access to the array
At the same time, in reality no C # programmer will write code with GC.Collect and a very small part of programmers will make an error in the for loop.
What is the point of comparing guaranteed ineffective C # code even with regular C ++ code? Is that to prove their point.
Fair comparison
To compare languages honestly - it is necessary to compare the type code in both languages. That is such a code that can be found in programs with a probability of more statistical error.
For example, I will use the same bubble sorting array.
C ++ tests
For the case of C ++, I will test three options:
- C-style array (pointer)
- std :: array
- std :: vector
Each test will run 100 times and the result will be averaged.
Measurement codestd::chrono::high_resolution_clock::duration measure(std::function<void()> f, int n = 100)
{
auto begin = std::chrono::high_resolution_clock::now();
for (int i = 0; i < n; i++)
{
f();
}
auto end = std::chrono::high_resolution_clock::now();
return (end - begin) / n;
}
C-style
void c_style_sort(int *m, int n)
{
for (int i = 0; i < N - 1; i++)
for (int j = i + 1; j < N; j++) {
if (m[i] < m[j])
{
int tmp = m[i];
m[i] = m[j];
m[j] = tmp;
}
}
}
void c_style_test()
{
int* m = new int[N];
for (int i = 0; i < N; i++)
{
m[i] = i;
}
c_style_sort(m, N);
delete[] m;
}
, , .
std::array
void cpp_style_sort(std::array<int, N> &m)
{
auto n = m.size();
for (int i = 0; i < n-1; i++)
for (int j = i + 1; j < n; j++) {
if (m[i] < m[j])
{
int tmp = m[i];
m[i] = m[j];
m[j] = tmp;
}
}
}
void cpp_style_test()
{
std::array<int, N> m;
for (int i = 0; i < N; i++)
{
m[i] = i;
}
cpp_style_sort(m);
}
, , .
C++ , std::array , , . std::array .
std::vector
void vector_sort(std::vector<int> &m)
{
auto n = m.size();
for (int i = 0; i < n - 1; i++)
for (int j = i + 1; j < n; j++) {
if (m[i] < m[j])
{
int tmp = m[i];
m[i] = m[j];
m[j] = tmp;
}
}
}
void vector_test()
{
std::vector<int> m;
m.reserve(N);
for (int i = 0; i < N; i++)
{
m.push_back(i);
}
vector_sort(m);
}
std::array. std::vector — , std::array. vector .
C#
:
- unsafe ()
- System.Collections.Generic.List
«» , GC.Collect, .
, .
static long Measure(Action f, int n = 100)
{
var sw = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < n; i++)
{
f();
}
return sw.ElapsedMilliseconds / n;
}
static void ArrayTest()
{
var m = new int[N];
for (int i = 0; i < m.Length; i++)
{
m[i] = i;
}
ArraySort(m);
}
static void ArraySort(int[] m)
{
for (int i = 0; i < m.Length - 1; i++)
for (int j = i + 1; j < m.Length; j++)
{
if (m[i] < m[j])
{
int tmp = m[i];
m[i] = m[j];
m[j] = tmp;
}
}
}
— for m.Length ( ). JIT .
unsafe
static unsafe void UnsafeTest()
{
var m = new int[N];
fixed(int* ptr = &m[0])
{
for (int i = 0; i < N; i++)
{
ptr[i] = i;
}
UnsafeSort(ptr, N);
}
}
static unsafe void UnsafeSort(int* m, int n)
{
for (int i = 0; i < n - 1; i++)
for (int j = i + 1; j < n; j++)
{
if (m[i] < m[j])
{
int tmp = m[i];
m[i] = m[j];
m[j] = tmp;
}
}
}
, , ( ).
fixed array, .
List
static void ListTest()
{
var m = new List<int>(N);
for (int i = 0; i < N; i++)
{
m.Add(i);
}
ListSort(m);
}
static void ListSort(List<int> m)
{
var n = m.Count;
for (int i = 0; i < n - 1; i++)
for (int j = i + 1; j < n; j++)
{
if (m[i] < m[j])
{
int tmp = m[i];
m[i] = m[j];
m[j] = tmp;
}
}
}
, List JIT, .
Visual Studio 2015, .NET Framework 4.6. Release, .
:
| x86 | x64 |
---|
(++) -style | 55ms | 55ms |
(++) std::array | 0ms (52ms) | 65ms |
(++) std::vector | 100ms | 65ms |
(C#) | 67ms | 90ms |
(C#) unsafe | 63ms | 105ms |
(C#) List | 395ms | 390ms |
x86 std::array, 0. , C-style .
- — ( )
- C# C++ 20%-50% ( )
- x64 (, )
—
github.com/gandjustas/PerfTestCSharpVsCPP« »
C# — . . C++ «» . C++, . , .
C++. , C++ , C++ . .
Update
:
- std::swap C++
- .at [],
- .NET Native
:
| x86 | x64 |
---|
(++) -style | 60ms | 52ms |
(++) std::array | 51ms | 60ms |
(++) std::vector | 147ms | 81ms |
(C#) | 67ms | 90ms |
(C#) unsafe | 63ms | 105ms |
(C#) List | 395ms | 390ms |
(C# + .NET Native) | 62ms | 59ms |
(C# + .NET Native) unsafe | 63ms | 52ms |
(C# + .NET Native) List | 274ms | 282ms |
.NET Native , C++.
- std::swap .
:
github.com/gandjustas/PerfTestCSharpVsCPP