V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
Joker123456789
V2EX  ›  分享创造

Magician 1.1.6 发布,采用事件组管理机制

  •  
  •   Joker123456789 · 2021-05-02 13:25:36 +08:00 · 988 次点击
    这是一个创建于 1089 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Magician 1.1.6,作为第一个正式的版本,内部对 NIO 的实现部分做了大量优化与重构,采用了事件组管理机制,具体模型如下图所示:

    avatar

    采用了两个事件组来进行事件和线程池的管理,一个叫 ioEventGroup,一个叫 workerEventGroup,都是通过 EventGroup 类创建。 每个 EventGroup 都对应一个 EventRunner,每个 EventRunner 对应一个任务队列,可以管理多个事件。 当队列空了以后,可以去其他的 EventRunner 窃取任务,不会造成资源浪费。

    ioEventGroup 是用来管理 Selector 的,一个端口对应一个 EventRunner 里的一个事件,也就是说如果要监听多个端口就需要在 ioEventGroup 初始化多个 EventRunner,这么做是因为 EventRunner 是按顺序消费事件的,如果多个监听事件都给一个 EventRunner 管理,可能会执行不到后面的事件,因为 Selector 是一个死循环 他会一直占用当前线程。

    workerEventGroup 是用来管理 业务事件的,一个连接对应一个 EventRunner,一个 EventRunner 对应多个连接,当连接里有了 read 事件就会往 EventRunner 里添加一个事件,EventRunner 会按顺序消费这些事件,在消费时 如果发现协议报文不完整会立刻停止该事件 继续执行下一个,如果报文完整会调用 handler 执行业务逻辑。 建议按照 CPU 的核心数来合理的设置 workerEventGroup 里的 EventRunner 数量。

    具体如何使用

    一、创建 TCP 服务(默认使用 http 解码器)

    创建 Handler

    public class DemoHandler implements MagicianHandler<MagicianRequest> {
    
        @Override
        public void request(MagicianRequest magicianRequest) {
            // 响应数据
            magicianRequest.getResponse()
                    .sendJson(200, "{'status':'ok'}");
        }
    }
    

    创建服务(默认线程池配置)

    Magician.createTCPServer()
                        .httpHandler("/", new DemoHandler())
                        .bind(8080);
    

    创建服务(自定义线程池配置)

    EventGroup ioEventGroup = new EventGroup(1, Executors.newCachedThreadPool());
    EventGroup workerEventGroup = new EventGroup(10, Executors.newCachedThreadPool());
    
    // 当前 EventRunner 没任务的时候,允许从其他 EventRunner 窃取任务
    workerEventGroup.setSteal(EventEnum.STEAL.YES);
    
    Magician.createTCPServer(ioEventGroup, workerEventGroup)
                        .httpHandler("/", new DemoHandler())
                        .bind(8080);
    

    创建服务(监听多端口)

    // 监听几个端口,ioEventGroup 的第一个参数就写几
    EventGroup ioEventGroup = new EventGroup(2, Executors.newCachedThreadPool());
    EventGroup workerEventGroup = new EventGroup(10, Executors.newCachedThreadPool());
    
    // 当前 EventRunner 没任务的时候,允许从其他 EventRunner 窃取任务
    workerEventGroup.setSteal(EventEnum.STEAL.YES);
    
    TCPServer tcpServer = Magician
                             .createTCPServer(ioEventGroup, workerEventGroup)
                             .httpHandler("/", new DemoHandler())
    
    tcpServer.bind(8080);
    tcpServer.bind(8088);
    

    二、创建 WebSocket

    只需要在创建 http 服务的时候加一个 handler 即可

    Magician.createTCPServer()
                        .httpHandler("/", new DemoHandler())
                        .webSocketHandler("/websocket", new DemoSocketHandler())
                        .bind(8080);
    

    三、创建 UDP 服务

    Magician.createTCPServer()
                        .httpHandler("/", new DemoHandler())
                        .webSocketHandler("/websocket", new DemoSocketHandler())
                        .bind(8080);
    

    除了这种写法,也可以单独创建 handler,在这里 add 进去

    官网:http://magician-io.com

    感谢

    最后需要感谢一下 曾经指出我项目中的 不足与错误点的人。因为你们我才能逐渐走上一个正确的方向,目前的版本虽然也不是很完美,性能,设计上 肯定还有很多可以优化的地方,但是已经不存在之前那个空转的低级错误了, IO 和上层协议也已经分开了,报文解码器也可自定义了。

    为了不打扰到你们,所以我选择 不艾特 了。

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5741 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 41ms · UTC 02:21 · PVG 10:21 · LAX 19:21 · JFK 22:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.