C# и C++ смешанное программирование и анализ производительности

искусственный интеллект

резюме:

Как мы все знаем, использование C# в качестве интерфейса намного эффективнее, чем разработка на C++, но в случае проблем с производительностью нам приходится использовать C++ для некоторых модулей, а затем нам нужно использовать C# и C++ для смешанного программирования. В этой статье представлены два метода гибридного программирования и сравнение производительности.

Среда разработки:

I5-8400 CPU 2.8G 8G, Win10 64Bit, VS2017 (параметры разработки C++), C++, C# — все используют платформу x32, а для проверки производительности используется версия Release.

Протестируйте производительность проекта на чистом C++:

1. Новое пустое решение: Файл|Новый|Проект|Установлено|Шаблон|Другие типы проектов|Решение Visual Studio|Пустое решение

2. Новый проект C++: щелкните правой кнопкой мыши Решение|Добавить|Новый проект|Установлено|Visual C++|Консольная программа Win32, сгенерируйте проект в соответствии с настройками по умолчанию.

3. Создайте новую платформу x32 в диспетчере конфигураций и удалите другие платформы.

4. Создайте новую CppFunction и добавьте тестовый код.Полный код выглядит следующим образом, а результат программы: Результат: 1733793664 Прошло:65

// CppFunction.h

#pragma once

class CppFunction

{

public:

    CppFunction(){}

    ~CppFunction(){}

    int TestFunc(int a, int b);

};

// CppFunction.cpp

#include "stdafx.h"

#include "CppFunction.h"

class CCalc

{

public:

    CCalc(int a, int b)

    {

        m_a = a;

        m_b = b;

    }

    int Calc()

    {

        if (m_a % 2 == 0){

            return m_a + m_b;

        }

        if (m_b % 2 == 0){

            return m_a - m_b;

        }

        return m_b - m_a;

    }

private:

    int m_a;

    int m_b;

};

int CppFunction::TestFunc(int a, int b)

{

    CCalc calc(a, b);

    return calc.Calc();

}

// PureCpp.cpp: определяет точку входа для консольного приложения.

//

#include "stdafx.h"

#include <iostream>

#include <windows.h>

#include "CppFunction.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])

{

    DWORD start = ::GetTickCount();

    CppFunction cppFunction;

    int result = 0;

    for (int i = 0; i < 10000; i++){

        for (int j = 0; j < 10000; j++){

            result += cppFunction.TestFunc(i, j);

        }

    }

    DWORD end = ::GetTickCount();

    cout << "Result: " << result << " Elapsed: " << end - start << endl;

    return 0;

}

 

Протестируйте чистую производительность проекта Csharp:

1. Создайте новый проект PureCsharp: щелкните правой кнопкой мыши Решение|Добавить|Новый проект|Установлено|Другие языки|Visual C#|Консольное приложение, сгенерируйте проект в соответствии с настройками по умолчанию.

2. Создайте новую платформу x32 в диспетчере конфигураций, удалите другие платформы и снимите флажок [Создать новую платформу решения], иначе он сообщит, что платформа x32 уже существует.

3. Скопируйте код в проект C++ и внесите некоторые изменения Полный код выглядит следующим образом, результат программы: Результат: 1733793664 Прошло: 607

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace PureCsharp

{

    class CCalc

    {

        public CCalc(int a, int b)

        {

            m_a = a;

            m_b = b;

        }

        public int Calc()

        {

            if (m_a % 2 == 0)

            {

                return m_a + m_b;

            }

            if (m_b % 2 == 0)

            {

                return m_a - m_b;

            }

            return m_b - m_a;

        }

        private int m_a;

        private int m_b;

    }

    class CppFunction

    {

        public int TestFunc(int a, int b)

        {

            CCalc calc = new CCalc(a, b);

            return calc.Calc();

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

             DateTime start = System.DateTime.Now;

            CppFunction cppFunction = new CppFunction();

            int result = 0;

            for (int i = 0; i < 10000; i++){

                for (int j = 0; j < 10000; j++){

                    result += cppFunction.TestFunc(i, j);

                }

            }

            DateTime end = System.DateTime.Now;

            System.Console.WriteLine("Result: " + result + " Elapsed: " + (end - start).Milliseconds);

       }

    }

}

 

Анализ производительности:

Как видно из приведенного выше сравнения, C# требует почти в 10 раз больше времени, чем C++ для одной и той же функции.Основная причина в этом примере заключается в том, что C++ может использовать эффективные объекты стековой памяти (CCalc), в то время как все объекты в C# можно разместить только в управляемой куче.

Управляемый гибрид C++:

1. Создайте новый консольный проект C#, назовите его CSxingneng, используйте его для вызова проекта C++ и измените каталог сборки на: ..\x32\Release\

2. В CLR создайте новый проект CLR C++ DLL и назовите его C++1.

3. Добавьте класс CppFunction в C++1 и скопируйте код, полный код выглядит следующим образом, результат программы: Результат: 1733793664 Прошло: 325

// CppFunction.h

#pragma once

public ref class CppFunction

{

public:

    CppFunction(){}

    ~CppFunction(){}

    int TestFunc(int a, int b);

};

// CppFunction.cpp

#include "CppFunction.h"

class CCalc

{

public:

    CCalc(int a, int b)

    {

        m_a = a;

        m_b = b;

    }

    int Calc()

    {

        if (m_a % 2 == 0){

            return m_a + m_b;

        }

        if (m_b % 2 == 0){

            return m_a - m_b;

        }

        return m_b - m_a;

    }

private:

    int m_a;

    int m_b;

};

int CppFunction::TestFunc(int a, int b)

{

    CCalc calc(a, b);

    return calc.Calc();

}

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace CSxingneng

{

    class Program

    {

        static void Main(string[] args)

        {

            DateTime start = System.DateTime.Now;

            CppFunction cppFunction = new CppFunction();

            int result = 0;

            for (int i = 0; i < 10000; i++)

            {

                for (int j = 0; j < 10000; j++)

                {

                    result += cppFunction.TestFunc(i, j);

                }

            }

            DateTime end = System.DateTime.Now;

            System.Console.WriteLine("Result: " + result + " Elapsed: " + (end - start).Milliseconds);

        }

    }

}

 

Анализ производительности:

После использования смешанного программирования производительность в некоторой степени улучшилась, но она все еще намного хуже, чем простой проект на C++.

Перенесите логику в основной функции C# в проект C++1, то есть добавьте следующий статический метод, пока метод вызывается на C#, результат программы: Результат: 1733793664 Прошло: 325

int CppFunction::Test()

{

    DWORD start = ::GetTickCount();

    CppFunction cppFunction;

    int result = 0;

    for (int i = 0; i < 10000; i++){

        for (int j = 0; j < 10000; j++){

            result += cppFunction.TestFunc(i, j);

        }

    }

    DWORD end = ::GetTickCount();

    cout << "Result: " << result << " Elapsed: " << end - start << endl;

    return result;

}

Это не становится быстрее.По оценкам, когда C++ компилируется с использованием метода [поддержки среды выполнения общего языка], преимущества производительности C++ не могут быть реализованы.

Смесь DLLImport:

1. Создайте новый непустой проект DLL C++ с именем NativeDLLCpp.

2. Скопируйте класс CppFunction из PureCpp.

3. Код следующий, рабочий результат: Результат: 1733793664 Прошло: 75

// NativeDLLCpp.cpp: определяет экспортированные функции приложения DLL.

//

#include "stdafx.h"

#include <iostream>

#include <windows.h>

#include "CppFunction.h"

using namespace std;

#ifdef __cplusplus

#define TEXPORT extern "C" _declspec(dllexport)

#else

#define TEXPORT _declspec(dllexport)

#endif

TEXPORT int Test()

{

    DWORD start = ::GetTickCount();

    CppFunction cppFunction;

    int result = 0;

    for (int i = 0; i < 10000; i++){

        for (int j = 0; j < 10000; j++){

            result += cppFunction.TestFunc(i, j);

        }

    }

    DWORD end = ::GetTickCount();

    cout << "C++ Result: " << result << " Elapsed: " << end - start << endl;

    return result;

}

    public class NativeDLLCpp

    {

        [DllImport("NativeDLLCpp.dll")]

        public static extern int Test();

    }

    class Program

    {

        static void Main(string[] args)

        {

            DateTime start = System.DateTime.Now;

            int result = NativeDLLCpp.Test();

            DateTime end = System.DateTime.Now;

            System.Console.WriteLine("Result: " + result + " Elapsed: " + (end - start).Milliseconds);

        }

}

 

Анализ производительности:

Почти такая же производительность, как у проектов на чистом C++.

Зависимости проекта должны быть установлены вручную.

Метод совместной отладки: изменение свойств проекта C# | отладка | включение отладки собственного кода