游戏后台里的通用技术之异步处理和回调

.什么是回调函数?
回调在不用的语言可以用不同的实现手法,比如C/C++一般使用函数指针,C#这类没有指针的语言可以使用委托,回调的本质上是先用函数指针存储函数
的地址,在处理完某个事件/或者满足某个条件的时候调用函数来处理。


2.为什么需要回调了?
在game后台很多处理需要异步的经行,这样才能保证后台程序的高效性。既然需要异步处理,那就是在某个时间点后或者满足某个条件后调用预先指定的函


数。这个就叫做回调。


3.如何设计一个通用的回调架构


从需求开始:
假想一个场景需求我们要异步处理对DB的数据处理,比如查询,修改数据都必须是异步的(使用SQL对db的查询一般是同步过程,也就是你select或者insert


的时候如果数据没有返回,这时候是不能接着处理下面的语句的,想象下在一个要处理几千玩家的服务器这绝对是不予需的)。那么如何设计了?
接着往下看。




//先的有一个抽象基类,提供一个回调接口run()函数,这样利用多态在调用run的时候,会根据实际的子类对象调用到子类的run
struct runnable
{

   virtual void run() = 0;

   virtual ~runnable() {};

};

具体实现 callback.h

#ifndef __CALLBACK_H_
#define __CALLBACK_H_
//#include ""

struct runnable
{
  virtual ~runnable() {};
  virtual void run() = 0;  //回调接口
};


template <typename FUN>
class CCallFun0 : public runnable
{
public:
    CCallFun0(FUN fun) { m_fun = fun; }
    virtual void run() 
    {
        m_fun();
    }
private:
    FUN m_fun;
};

template<typename FUN,typename PAR>
class CCallFun1:public runnable
{
public:
    CCallFun1(FUN fun,PAR par)
        :m_fun(fun) 
        ,m_par(par)
    {}
    virtual ~CCallFun1() {};
    virtual void run() 
    {
        m_fun(m_par);
    }
private:
    FUN  m_fun;
    const PAR  m_par;
};

template<typename FUN,typename PAR1,typename PAR2>
class CCallFun2:public runnable
{
public:
    CCallFun2(FUN fun,PAR1 par1,PAR2 par2)
        :m_fun(fun),
        m_par1(par1),
        m_par2(par2)
    {}
    
    virtual void run() 
    {
        m_fun(m_par1,m_par2);
    }

private:
    FUN m_fun;
    const PAR1 m_par1;
    const PAR2 m_par2;
};

#endif





测使用 


#include "CallBack.h"
void test(int index)
{
    std::cout << index;
}


void strtest(std::string str)
{
    std::cout << str;
}


template < typename FUN, typename PARA >
inline runnable * make_fun_runnable(FUN fun, PARA para)
{
    return new CCallFun1<FUN, PARA>(fun, para);
}


int _tmain(int argc, _TCHAR* argv[])
{
    runnable* runbale = make_fun_runnable(test,5);
    runbale->run();


    runbale = make_fun_runnable(strtest,"ABCD");
    runbale->run();


return 0;
}


根据参数个数不同,可以模仿上面增加类来支持


//那么在DB的查询中如何异步来使用了 大概流程如下


定义回调函数 比如加载玩家信息


void LoadRoleInfoFromDB(int roleid, dataset * data)
{
   //dataset为db查询的返回结果,根据实际情况类型会不同 
   //如mysql的 dataset可能为 ::mysqlpp::StoreQueryResult
   //伪代码如下
   CPlayer* player = GetPlayer(roleid); 
   if (player == NULL)
   {
       return;
   }
   struct playerinfo info; 
   //一般会把DB的信息解码成自定义结构体
   Encode(data,info);
   player->SetInfo(data); 



//某个Role的请求查询伪代码


runnable* runbale = make_fun_runnable(LoadRoleInfoFromDB,player->getroleid());  
//放入异步队列
SQLQUEUE->PushQueue(SQL,runbale);  //push到队列后


异步处理队列
在处理完毕后
dataset  data //查询到的结果
//这个地方需要修改下,让run可以接受参数 
//run里就调用LoadRoleInfoFromDB(roleid,data);
runbale->run(data); 


当然还可以用在更多场景,

比如在一个定时器里在一个时间间隔内调用回调函数

待续




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值