резюме:
Как мы все знаем, использование 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# | отладка | включение отладки собственного кода