別のC ++とC#のパフォーマンス比較

この記事に触発されました

C ++およびC#のパフォーマンスに関して3つの意見があります。

C ++を知っている(または知っていると思う)人は、C ++が数倍または数桁高速であると信じています。
C ++とC#を知っている人は、通常のタスクではC ++のパフォーマンスは不要であり、必要な場合はC#コードを不可能に最適化することが可能であることを知っています。 C ++の最適化の上限はC#の場合よりも高くなりますが、そのようなレコードは必要ありません。
C#のみを知っている人は、その速度で問題を経験したことはありません。

最初のカテゴリの人々は、常に自分の主張を証明しようとしています。 同時に、最適化されたC ++コードと最も悲観的なC#コードの例を示します。

「典型的な」比較の例


画像
C#を知っているプログラマーは、すぐに2つのエラーを見ることになります。
  1. GC.Collectの呼び出し。ガベージコレクションの実行時に行われた最適化を無効にします。
  2. 配列への呼び出しごとに境界チェックを排除しないことが保証されているforループを使用します。

同時に、実際には、C#プログラマーがGC.Collectでコードを書くことはなく、プログラマーのごく一部がforループでエラーを起こします。
保証された非効率的なC#コードを通常のC ++コードと比較する意味は何ですか? 彼らの主張を証明しない限り。

公正な比較


言語を正直に比較するには、両方の言語のサンプルコードを比較する必要があります。 つまり、統計誤差よりも大きい確率でプログラムで見つけることができるようなコード。

例として、同じバブルソートの配列を使用します。

C ++のテスト


C ++の場合、3つのオプションをテストします。
  1. Cスタイルの配列(ポインター)
  2. std ::配列
  3. std ::ベクトル

各テストは100回実行され、結果は平均化されます。
測定コード
std::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#


:
  1. unsafe ()
  2. 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, .

:
x86x64
(++) -style55ms55ms
(++) std::array0ms (52ms)65ms
(++) std::vector100ms65ms
(C#)67ms90ms
(C#) unsafe63ms105ms
(C#) List395ms390ms

x86 std::array, 0. , C-style .



github.com/gandjustas/PerfTestCSharpVsCPP

« »


C# — . . C++ «» . C++, . , .

C++. , C++ , C++ . .

Update


:

:
x86x64
(++) -style60ms52ms
(++) std::array51ms60ms
(++) std::vector147ms81ms
(C#)67ms90ms
(C#) unsafe63ms105ms
(C#) List395ms390ms
(C# + .NET Native)62ms59ms
(C# + .NET Native) unsafe63ms52ms
(C# + .NET Native) List274ms282ms

.NET Native , C++.
- std::swap .

: github.com/gandjustas/PerfTestCSharpVsCPP

Source: https://habr.com/ru/post/J266373/


All Articles