• skynet源码分析:消息


    消息队列mq

    消息队列是skynet的核心功能之一,它的功能说白了就是入队出队,先进先出,这个数据结构都有讲过。源码实现在skynet_mq.h和skynet_mq.c中。

    skynet的消息队列实际上是有两种,一种是全局消息队列,一种是服务消息队列。每个服务都有自己的消息队列,每个服务消息队列中都有服务的handle标识。这个涉及到消息的派发,这里就不展开了。每个服务消息队列被全局消息队列引用。

    全局消息队列用的是经典的链表来实现的,而服务的消息队列用的是比较不直观,可能对有些人来说理解起来特别困难的循环数组来实现的。而且数组空间不够的时候,会动态扩展,容量扩展为当前容量的2倍。

    消息队列的出队入队函数名都比较简单而且明了,push/pop。这个名字可能会带来一定的误解,如果改成enqueue/dequeue的话,就更符合它的实际功能。

    消息机制之消息处理

    skynet的消息机制准备拆成三个部分来讲,第一部分是接收处理,第二部分是分发,第三部分是消息注册。

    skynet是单进程多线程的,线程的种类有monitor/timer/socket/worker,monitor就是监控服务是不是陷入死循环了。timer是skynet自己实现的定时器。socket是负责网络的,这个应该是最容易被理解的。worker就是工作线程了,monitor/timer/socket都只有一个线程,唯独worker有多个线程,是可配的,不配的话是8个线程。每个工作线程有个叫worker_parm的参数。

    在开始讲线程之前还需要回顾一下消息队列,在第2篇中讲过全局消息队列是链表,里面链了工作消息队列,而工作消息队列内部使用的是循环数组。
    另外还要回顾一下消息的handle,每个服务都有运行时一个独一无二的handle,这个handle可以跟名字绑定。
    接收处理

    先总结一下,skynet_context_message_dispatch这个函数实际上就是不停地从全局消息队列里取工作队列,取到了以后呢,就一直处理这个队列里的消息。为了避免某个队列占用太多cpu,当前队列处理到一定的量,就把机会让给全局消息队列里的其它工作队列,把自己又放回全局消息队列。而这个处理的量是根据创建线程时thread_param里的weight权重来判定的,权重越大,流转的就越快,也就是说处理某个队列的消息数量就越少。这就是消息处理的主流程机制。

    在主流程之外,还有monitor的触发和取消,每次处理前,触发monitor的检查。处理完了,取消monitor的检查。

     
    分发
    消息的处理实际上就是对工作队列里的消息不停地调回调函数。那么消息是怎么放进消息队列的呢。带着这个疑问,让我们从lua层开始追根溯源。

    在lua层有两个api,一个是skynet.send,这个是非阻塞发消息。另一个是skynet.call,这个是阻塞式发完消息等回应。skynet.call使用一个session来实现等待,这个session实际就是一个自增的数字,溢出了以后又从1开始。

    skynet.send实际上就是往目标服务的消息队列里增加一条消息。
    注册

    skynet的消息注册,C服务和lua服务设置回调走的函数是不同的。C的回调可以直接调,但是lua的回调不行,它需要一个默认的回调C函数,将返回参数转换为lua能理解的格式,遵循lua的api协议,传递到lua层。

    当服务是lua实现的时候,skynet底层核心框架在处理完消息以后,回调lua层服务的回调函数时,要先经过一次lua api协议的处理,将参数准备好以后,然后调用lua服务中的回调函数。

    消息

    每条 skynet 消息由 6 部分构成:消息类型、session 、发起服务地址 、接收服务地址 、消息 C 指针、消息长度。

    每个 skynet 服务都可以处理多类消息。在 skynet 中,是用 type 这个词来区分消息的。但与其说消息类型不同,不如说更接近网络端口 (port) 这个概念。每个 skynet 服务都支持 255 个不同的 port 。消息分发函数可以根据不同的 port 来为不同的消息定制不同的消息处理流程。

    消息队列结构分析


    队列一般可以用链表来模拟,用两个指针,分别指向头节点和尾节点。尾节点指向插入数据的方向,头节点指向消耗数据的方向。skynet全局消息队列也用到了上面的数据结构:

    https://blog.csdn.net/zxm342698145/article/details/80847301

     

    消息调度

    参考:

    《skynet_summary》

    《Skynet框架之菜鸟手册》

    skynet源码分析(2)--消息队列mq
  • 相关阅读:
    HTTPs与HTTP的区别&HTTPs如何建立连接
    HTTP协议常见状态码和字段
    服务器负载均衡
    ARP协议工作原理
    C++智能指针
    C++类型转换
    Rust 只出现一次的数字 两种解法
    Rust 存在重复元素 两种解法
    Rust 旋转数组
    Rust 动态规划 买卖股票的最佳时机 II
  • 原文地址:https://www.cnblogs.com/losophy/p/9203478.html
Copyright © 2020-2023  润新知