zoukankan      html  css  js  c++  java
  • 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#项目属性|调试|启用本机代码调试

  • 相关阅读:
    Oracle 删除某个用户下的所有对象,执行需谨慎
    ORACLE常用性能监控SQL
    mysql千万级大数据SQL查询优化
    qt小例子:实现阿里云物联网设备登录信息计算器
    mqtt协议
    亚马逊物联网平台c-sdk的使用
    esp32-cam开发环境搭建
    qt小例子:实现选值框和滑块同步变化
    在qt5中使用qtmqtt库
    将short类型转换为char类型
  • 原文地址:https://www.cnblogs.com/zhuyingchun/p/9127068.html
Copyright © 2011-2022 走看看