共享单车(六):分发消息服务

把外部收到的消息,转化成内部事件,也就是 data->msg->event 的解码过程,然后再把事件投递至线池的消息队列,由线程池调用其process 方法对事件进行处理,最终调用每个 event 的 handler 方法来处理 event,此时每个 event handler 需要 subscribe 该 event 后才会被调用到。

可以看成是一个中转站,整合了线程池与 libevent 库。将网络接口接收到的数据变为具体事件请求交给线程池处理,线程池处理完后会返回相应的事件响应对象。再由该类对象处理好事件响应对象返回数据给网络接口类,网络接口类再把数据发回给客户端。

封装

在这里插入图片描述

class DispatchMsgService
{
protected:
    DispatchMsgService();
public:

    virtual ~DispatchMsgService();

    virtual BOOL open();
    virtual void close();

    virtual void subscribe(u32 eid, iEventHandler* handler);
    virtual void unsubscribe(u32 eid, iEventHandler* handler);

    //把事件投递到线程池中进行处理
    virtual i32 enqueue(iEvent* ev);

    //线程池回调函数
    static void svc(void* argv);

    //对具体的事件进行分发处理
    virtual iEvent* process(const iEvent* ev);

    static DispatchMsgService* getInstance();

    iEvent* parseEvent(const char* message, u32 len, u32 eid);

    void handleAllResponseEvent(NetworkInterface* interface);

protected:

    thread_pool_t* tp;

    static DispatchMsgService* DMS_;

    typedef std::vector<iEventHandler*> T_EventHandlers;
    typedef std::map<u32, T_EventHandlers > T_EventHandlersMap;
    T_EventHandlersMap subscribers_;

    bool svr_exit_;

    static std::queue<iEvent*> response_events;//响应的事件
    static pthread_mutex_t   queue_mutex;//线程互斥锁,锁队列
};

流程

首先 DispatchMsgService 类会创建唯一的一个对象(单例模式),该对象调用 open() 方法启动线程池。再调用 enqueue(iEvent* ev) 函数,他会传入一个 iEvent 对象,组装一个任务节点绑定任务处理函数为DispatchMsgService::svc,之后交给线程池任务队列。线程池会调用DispatchMsgService::svc函数,该函数会调用DispatchMsgService::process(const iEvent* ev)函数,如果此时该对象注册了处理函数,就创建一个UserEventHandler类对象并调用该对象的handler函数进行事件的处理。

1.启动线程池

BOOL DispatchMsgService::open()
{
    svr_exit_ = FALSE;

    thread_mutex_create(&queue_mutex);
    tp = thread_pool_init();

    return tp ? TRUE : FALSE;
}

void DispatchMsgService::close()
{
    svr_exit_ = TRUE;

    thread_pool_destroy(tp);
    thread_mutex_destroy(&queue_mutex);
    subscribers_.clear();

    tp = NULL;
}

2.把事件投递到线程池中

i32 DispatchMsgService::enqueue(iEvent* ev)
{
    if (NULL == ev)
    {
        return -1;
    }

    thread_task_t* task = thread_task_alloc(0);

    task->handler = DispatchMsgService::svc;
    task->ctx = ev;

    return thread_task_post(tp, task);

    //return msg_queue_.enqueue(ev, 0);
}

3.线程池回调

void DispatchMsgService::svc(void* argv)
{
    DispatchMsgService* dms = DispatchMsgService::getInstance();
    iEvent* ev = (iEvent*)argv;
    if (!dms->svr_exit_)
    {
        LOG_DEBUG("DispatchMsgService::svc ...\n");
        iEvent* rsp = dms->process(ev);
        if (rsp)
        {
            rsp->dump(std::cout);
            rsp->set_args(ev->get_args());
        }
        else
        {
            //生成终止响应事件
            rsp = new ExitRspEv();
            rsp->set_args(ev->get_args());
        }

        thread_mutex_lock(&queue_mutex);
        response_events.push(rsp);
        thread_mutex_unlock(&queue_mutex);

    }
}

4.事件分发

iEvent* DispatchMsgService::process(const iEvent* ev)
{
    LOG_DEBUG("DispatchMsgService::process -ev: %p\n", ev);
    if (NULL == ev)
    {
        return NULL;
    }

    u32 eid = ev->get_eid();

    LOG_DEBUG("DispatchMsgService::process - eid: %u\n", eid);

    if (eid == EEVENTID_UNKOWN)
    {
        LOG_WARN("DispatchMsgService : unknow evend id %d", eid);
        return NULL;
    }

    //LOG_DEBUG("dispatch ev : %d\n", ev->get_eid());

    T_EventHandlersMap::iterator handlers = subscribers_.find(eid);
    if (handlers == subscribers_.end())	// 未订阅
    {
        LOG_WARN("DispatchMsgService : no any event handler subscribed %d", eid);
        return NULL;
    }

    iEvent* rsp = NULL;
    // 给订阅的user_event_handler都发一遍
    for (auto iter = handlers->second.begin(); iter != handlers->second.end(); iter++)
    {
        iEventHandler* handler = *iter;
        LOG_DEBUG("DispatchMsgService : get handler: %s\n", handler->get_name().c_str());

        rsp = handler->handle(ev);//推荐使用vector 或list 返回多个rsp 
    }

    return rsp;
}

相关知识

单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并且提供了全局访问该实例的方法。在C++中,单例模式的实现方式有多种。
在单例模式中,通常使用一个静态方法或者一个静态变量来保存实例。这个静态方法或者静态变量可以被所有需要访问该实例的对象共享,并且在第一次调用时创建实例。之后每次调用该方法或者访问该变量时,都返回同一个实例。

单例模式的特点:

  • 一个类只有一个实例;
  • 该实例在程序运行的整个周期内始终存在;
  • 该实例可以被全局访问;

应用

  • 单例模式可以用于控制资源的访问,例如数据库连接池、线程池等;
  • 它还可以用来确保系统中某些组件只有一个实例,例如配置文件管理器、日志记录器等。

实现单例模式的思路:

  • 一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);
  • 当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;
  • 同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。

1.饿汉式:单例实例在类装载时就构建,急切初始化。(预先加载法)

public class Test {
        private Test() {
        }
        public static Test instance = new Test();
        public Test getInstance() {
                return instance;
        }
}

优点:没有加锁,执行效率会提高。缺点:类加载时就初始化,浪费内存。

2.懒汉式:单例实例在第一次被使用时构建,延迟初始化。

class Test {
        private Test() {
        }
        public static Test instance = null;
        public static Test getInstance() {
                if (instance == null) {
              //多个线程判断instance都为null时,在执行new操作时多线程会出现重复情况
                        instance = new Singleton2();
                }
                return instance;
        }
}

优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁(在“线程安全”部分分享如何加锁)才能保证单例,但加锁会影响效率。

单例模式总结

要求: 在内存中只能生成一个对象

  1. 将构造函数私有化
  2. 在类中顶一个静态指针,在类之外初始化为空
  3. 在类中再顶一个返回值为类对象指针的静态成员函数

单例模式(C++)
C++之单例模式

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python是一种强大的编程语言,广泛应用于数据分析和科学计算。共享单车数据分析是指通过对共享单车系统中的数据进行统计、分析和挖掘,以从中提取有价值的信息和洞察力。在技术方面,Python提供了许多用于数据处理和分析的库和工具,例如NumPy、Pandas和Matplotlib等。 Python在共享单车数据分析中的应用非常广泛。首先,Python具有简单易学的语法,使得初学者和专业人士都能够快速上手。其次,Python拥有丰富的数据处理和分析库,可以方便地进行数据清洗、筛选和转换。而且,Python还提供了强大的可视化工具,使得数据分析结果可以以图表的形式直观展示。 在共享单车数据分析中,通常需要进行以下几个步骤。首先,需要从共享单车系统中获取原始数据,包括骑行时间、地点、骑行距离等信息。其次,可以使用Python的Pandas库对数据进行清洗和预处理,比如去除异常值、处理缺失值等。然后,可以使用Python的统计分析库,如Scipy和Statsmodels,进行数据分析和模型建立。最后,可以使用Matplotlib进行数据可视化,生成各种图表和报表,以便更好地理解数据,发现潜在的模式和规律。 总之,Python在共享单车数据分析中具备良好的适用性和实用性,可以帮助我们更好地理解共享单车系统的运行情况,提供决策支持和优化方案。CSDN是一个开发者社区网站,上面有很多关于Python共享单车数据分析的教程和案例分享,可以供初学者和专业人士参考学习。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞大圣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值