C#与C++混合编程及性能分析

272 阅读3分钟

概要:

  众所周知,用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,并添加测试代码,完整代码如下,程序结果:Result: 1733793664 Elapsed: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++项目中的代码复制过来稍作改动,完整代码如下,程序结果:Result: 1733793664 Elapsed: 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#的耗时几乎是C++的10倍,这个例子里的主要原因是,C++可以使用高效的栈内存对象(CCalc),而C#所有对象只能放在托管堆中。

托管C++混合方式:

  1. 新建C#控制台项目,命名为CSxingneng,使用它来调用C++项目,修改生成目录为:..\x32\Release\

  2. 在CLR中,新建CLR C++DLL项目,命名为C++1。

  3. 在C++1中添加CppFunction类,并复制代码,完整代码如下,程序结果:Result: 1733793664 Elapsed: 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项目中,即添加如下的static方法,C#中只要调用该方法,程序结果:Result: 1733793664 Elapsed: 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. 新建非空的C++DLL项目,命名为NativeDLLCpp

  2. 将CppFunction类从PureCpp中复制过来

  3. 代码如下,运行结果:Result: 1733793664 Elapsed: 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#项目属性|调试|启用本机代码调试