利用C++/CLI 封装Native C++ 提升.NET web game性能

时间:2022-06-01 19:33:26

利用C++/CLI 封装Native C++ 提升.NET web game性能

   原帖:

http://www.cnblogs.com/warensoft/archive/2010/03/07/1680290.html

 

这段时间在做新项目的技术论证,其基本想法就是利用Flex调用远程WCF以及发送Socket请求,来实现远程通信,WCF负责实时性要求不高的操作,如聊天,邮件,交易,买卖等,而Socket的目的是提供实时战斗的服务。

无论是WCF,还是Socket,都会提供不少的游戏逻辑,当然,大家心里都有数,与C++相比C#在纯数值运算上慢的太多,但是提到语法简洁性,MS的数据访问组件支持,IDE的智能感知VC又相形见绌。

虽然C++/CLI不能够满足上面的各种要求,但是它却可以Native C++C#Adapter,来保证程序的优质性。本文的目的有两点:

         如何利用C++/CLI封装Native C++,并被C#调用

         被封装过的Native C++代码与C#代码在性能方面的对比

  1. C++/CLI封装Native C++,并被C#调用

    为了方便团队开发,我们通常要将C++代码编译成DLL,以方便.NET开发人员调用,因此,我们首先来编写一个Native C++的类,并编译成DLL。过程如下:

    1. VS2008VC++项目模板中,选择Win32项目中的 Win32 Project,并命名为NativeCPPDLL,如下图所示:

      利用C++/CLI 封装Native C++ 提升.NET web game性能

    2. 选择将其编译成DLL,如下图所示:

      利用C++/CLI 封装Native C++ 提升.NET web game性能

    3. 在项目中添加一个名为NativeCPP的类,基类结构如下图所示:

      利用C++/CLI 封装Native C++ 提升.NET web game性能

    4. NativeCPP的头文件(NativeCPP.h)代码如下:

      #pragma once

      #include "math.h"

      #ifndef GoWin_DLL_CLASS_EXPORTS

          //该类可导出

          #define GoWin_DLL_CLASS __declspec(dllexport)

      #else

          //该类可导入

          #define GoWin_DLL_CLASS __declspec(dllimport)

      #endif

         

      class GoWin_DLL_CLASS NativeCPP

      {

      public:

                    NativeCPP(void);

                    ~NativeCPP(void);

                    void Compute1();

                    void Compute2();

      }

    5. NativeCPPCPP文件(NativeCPP.cpp)的代码如下所示:

      #include "StdAfx.h"

      #include "NativeCPP.h"

         

      NativeCPP::NativeCPP(void)

      {

      }

         

      NativeCPP::~NativeCPP(void)

      {

      }

      void NativeCPP::Compute1 ()

      {

      for(int i=0;i<100000;i++)

      {

         for(int j=0;j<i;j++)

         {

         

         }

      }

      }

      void NativeCPP::Compute2 ()

      {

      for(int i=0;i< 30000000;i++)

      {

         pow(1.05,i);//pow函数是游戏里常用的数据增长公式

      }

      }

   

  1. 编译代码。
  2. 在解决方案中添加一个C++/CLI的类库,将命名为CPPWrapper如下图所示:

     

    利用C++/CLI 封装Native C++ 提升.NET web game性能

     

  3. CPPWrapper添加刚才编译好的DLL项目的引用,如下图所示,在该项目上点击右键,选择"Reference":

    利用C++/CLI 封装Native C++ 提升.NET web game性能

     

  4. 在弹出的对话框中选择Add New Reference,如下图所示:

     

    利用C++/CLI 封装Native C++ 提升.NET web game性能

     

  5. Projects里选择刚才建立的NativeCPPDLL项目。如下图所示:

     

    利用C++/CLI 封装Native C++ 提升.NET web game性能

     

  6. CPPWrapper里添加一个头文件,内容和名称都"NativeCPP.h"一样。
  7. CPPWrapper里添加一个名为NativeCPPWrapper的托管类,如下图所示:

    利用C++/CLI 封装Native C++ 提升.NET web game性能

    该类的结构与NativeCPP中的类结构完全一样,但是要在类中定义一个从DLL导入的Native C++类的指针,.h文件中的代码如下所示:

    #pragma once

    #include "NativeCPP.h"

    #define GoWin_DLL_CLASS_EXPORTS

    public ref class NativeCPPWrapper

    {

    private:

       NativeCPP*nativeCPP;//native c++类的指针

    public:

       NativeCPPWrapper(void);

    public:

       void Compute1();

       void Compute2();

    };

   

该类的CPP文件,完成就是对Native C++类的接口转换,其代码如下所示:

#include "StdAfx.h"

#include "NativeCPPWrapper.h"

   

NativeCPPWrapper::NativeCPPWrapper(void)

{

              this->nativeCPP =new NativeCPP();

}

void NativeCPPWrapper::Compute1()

{

              this->nativeCPP ->Compute1 ();

}

void NativeCPPWrapper::Compute2()

{

              this->nativeCPP ->Compute2 ();

}

  1. C++/CLI的项目属性里,将Common Language Runtime Support设置为Common Language Runtime Support(/clr),否则的话,将无法使用非托管的Native C++

    利用C++/CLI 封装Native C++ 提升.NET web game性能

     

  2. 现在可以建立一个C#的项目了,只要添加CPPWrapper的引用,就可以像调用C#写的DLL一样来调用C++/CLI写的类了,如下图所示:

    利用C++/CLI 封装Native C++ 提升.NET web game性能

  3. 如何你用的是64位的操作系统的话,直接调用会出错,这时要配置一个C#项目的编译选择,将编译的目标平台设置成"X86"。(请千万别把它读成"叉儿八六",你是专业计算机人员,应该说的专业点,它叫"艾克思八六")。如下图所示:

    利用C++/CLI 封装Native C++ 提升.NET web game性能

   

   

  1. 前面对如何利用C++/CLI封装原生C++代码,并被C#所调用作了一些说明,下面通过数据对比来说明这样做的意义。
    1. 实验说明:

该实验将进行如下几组测试

编号

说明

1

利用MFC调用NativeCPP DLL,并分别测试NativeCppCompute1()以及Compute2()两个函数所需要的时间

2

利用C# WinForm调用NativeCPPWrapperC++/CLI)来间接访问NativeCPP类中的Compute1()以及Compute2()两个函数,并检测所需要的时间。

3

利用C# WinForm直接调用C#编写的相同功能的Compute1()以及Compute2()两个函数,并检测所需要的时间。

说明:Compute1()里只有循环,Compute2()里包括了一个pow函数。

  1. 代码略
  2. 测试环境

    利用C++/CLI 封装Native C++ 提升.NET web game性能

  3. 测试结果(Debug版本)

编号

操作

时间

1

MFC 调用NativeCPP::Compute1()

14s

2

MFC调用NativeCPP::Compute2()

9s

3

C#调用NativeCPPWrapper::Compute1()

14s

4

C#调用NativeCPPWrapper::Compute2()

9s

5

C#调用C#写的Compute1()

19s

6

C#调用C#写的Compute2()

3s

  1. 结论

通过1234的数据,不难发现,利用C++/CLI封装过的Native C++在性能上基本没有什么损失(但是一定要在操作密集中的代码中封装,而不是调用密集型的代码)。135三组数据可说明,在单纯的循环上,C#要比C++慢很多。

debug模式下大量使用Pow函数的时候.net framework里提供的Math.Pow,要远远快于math.h中的pow函数,实验结果中几乎差了三倍!如果改成Release模式,C++中两函数的操作时间基本上都为0,当然C#的速度也有明显提高,但是要远远慢于C++