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

概要:

  众所周知,用C#做界面比C++开发效率要高得多,但在有性能问题的情况下不得不将部分模块使用C++,这时就需要使用C#与C++混合编程。本文给出了两种混合编程的方法以及性能对比。

开发环境:

  ThinkPad T430 i5-3230M 2.6G 8G,Win7 64Bit,VS2013(C++开发设置),C++,C#都采用x64平台,性能验证使用Release版本。

测试纯C++项目性能:

  1. 新建空解决方案:文件|新建|项目|已安装|模板|其他项目类型|Visual Studio解决方案|空白解决方案

  2. 新建PureCpp项目:右击解决方案|添加|新建项目|已安装|Visual C++|Win32控制台程序,按缺省设置生成项目

  3. 在配置管理器中新建x64平台,删除其他平台

  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项目性能:

  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++项目,修改生成目录为:..x64Release

  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#项目属性|调试|启用本机代码调试

原文地址:https://www.cnblogs.com/zhuyingchun/p/9127068.html