概要:ios
衆所周知,用C#作界面比C++開發效率要高得多,但在有性能問題的狀況下不得不將部分模塊使用C++,這時就須要使用C#與C++混合編程。本文給出了兩種混合編程的方法以及性能對比。編程
開發環境:windows
ThinkPad T430 i5-3230M 2.6G 8G,Win7 64Bit,VS2013(C++開發設置),C++,C#都採用x64平臺,性能驗證使用Release版本。ide
測試純C++項目性能:函數
1. 新建空解決方案:文件|新建|項目|已安裝|模板|其餘項目類型|Visual Studio解決方案|空白解決方案性能
2. 新建PureCpp項目:右擊解決方案|添加|新建項目|已安裝|Visual C++|Win32控制檯程序,按缺省設置生成項目測試
3. 在配置管理器中新建x64平臺,刪除其餘平臺spa
4. 新建CppFunction,並添加測試代碼,完整代碼以下,程序結果:Result: 1733793664 Elapsed: 109調試
// 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項目性能:code
1. 新建PureCsharp項目:右擊解決方案|添加|新建項目|已安裝|其餘語言|Visual C#|控制檯應用程序,按缺省設置生成項目
2. 在配置管理器中新建x64平臺,刪除其餘平臺,去掉【建立新的解決方案平臺】勾選,不然會報x64平臺已經存在
3. 將C++項目中的代碼複製過來稍做改動,完整代碼以下,程序結果:Result: 1733793664 Elapsed: 729
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#的耗時幾乎是C++的7倍,這個例子裏的主要緣由是,C++可使用高效的棧內存對象(CCalc),而C#全部對象只能放在託管堆中。
託管C++混合方式:
1. 新建C#控制檯項目,命名爲BenchCsharp,使用它來調用C++項目,修改生成目錄爲:..\x64\Release\
2. 新建C++DLL項目,命名爲DLLCpp,選擇空項目,生成成功,但因爲是空項目,不會真正生成dll文件
3. 在DLLCpp爲空項目時,在BenchCsharp中能夠成功添加引用,但當DLLCpp中添加類後,就不能成功添加引用了,已經添加的引用也會顯示警告
4. 修改DLLCpp項目屬性,右擊項目|屬性|配置屬性|常規|公共語言運行時支持,修改後就能夠成功引用了
5. 在DLLCpp中添加CppFunction類,並複製代碼,完整代碼以下,程序結果:Result: 1733793664 Elapsed: 405
// 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 BenchCsharp { 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#主函數中的邏輯轉移到DLLCpp項目中,即添加以下的static方法,C#中只要調用該方法,程序結果:Result: 1733793664 Elapsed: 405
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. 新建非空的C++DLL項目,命名爲NativeDLLCpp
2. 將CppFunction類從PureCpp中複製過來
3. 代碼以下,運行結果:Result: 1733793664 Elapsed: 125
// 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 << "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#項目屬性|調試|啓用本機代碼調試