C#與C++混合編程及性能分析

概要: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;
}
View Code

測試純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);
       }
    }
}
View Code

性能分析:

  從上面的對比能夠看出,一樣的功能,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();
}
View Code
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);
        }
    }
}
View Code

性能分析:

  使用混合編程後,性能獲得了必定程度的提高,但比起單純的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;
}
View Code

  並無變得更快,估計是當使用【公共語言運行時支持】方式編譯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;
}
View Code
    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);
        }
    }
View Code

性能分析:

  跟純C++項目性能幾乎一致。

  項目依賴項須要手動設置。

  實現聯調的方法:修改C#項目屬性|調試|啓用本機代碼調試

相關文章
相關標籤/搜索