美文网首页
多线程服务器的常见编程模型

多线程服务器的常见编程模型

作者: CP3fans | 来源:发表于2020-09-21 08:53 被阅读0次

    多线程服务器的常见编程模型

    IO Models

    image

    A ->[tcp send buffer] --->[tcp recv buffer]-> B

    Blocking IO : A send data 发送缓冲区满或 B recv data接收缓冲区空 会阻塞当前线程

    NonBlocking IO: 和Blocking IO不同的是,send或者recv直接返回错误(需要轮询调用)

    IO Multiplexing:通过Select/Poll/Epoll等系统调用监控多个连接上的读写事件

    Thread Models

    Blocking IO + One Thread Per Connection

    • Acceptor -> [New Thread]
    • 频繁创建销毁线程的时间开销,线程之间的切换也会有大量开销
    • 创建大量线程会消耗完系统内存

    Blocking IO + Thread Pool (Tomcat BIO)

    • Acceptor -> worker thread pool
    • 适合短连接,并发数有限

    IO Multiplexing + Thread Pool (Tomcat NIO)

    • Acceptor->[event queue]->Poller(select/poll/epoll)->worker(one of Thread Pool)

    IO Multiplexing + One Thread One Loop *

    • 线程数目基本固定
    • 高并发

    One Thread One Loop思想

    一个线程一个循环流程

    Loop结构

    void CReactor::Run()
    {
        //线程退出标志
        m_bShouldRun = true;
        while(m_bShouldRun)
        {
            //处理其他的任务
            handle_other_task();
            //利用select/pool/epoll等I/O多路复用监听各个连接(fd)的读写事件
            select_or_epoll_function();
            //处理各个连接(fd)的读写事件
            handle_io_event();
            //处理定时器
                    check_timer();
            //处理同步或者异步事件
            dispatch_event();
        }
    }
    

    线程分工(front)

    front线程交互

    AcceptReactor

    1、监听是否有新的客户端连接(Listenfd上是否有读事件发生)。

    2、有新连接则生成新连接的socket(clientfd),并将该socket传递给frontReactor。

    Q:线程之间如何传递?

    SendEvent Or PostEvent

    Q:新连接分配策略?

    Round Robin(轮询) 缺点:负载均衡有点问题

    TresultReactor

    1、订阅tserver发布的流水,接收到流水中的XTP报文,存到TradeResult(CachedFlow)中。

    FrontReactor

    1、通过Epoll或者Select系统调用监听该线程所负责Socket连接上的读写事件

    2、收包(收网络数据,放缓冲区,解包并处理) 发包(....)

    3、从TradeResult(cachedFlow)中读取从tserver发布的XTP报文,并处理。

    Q:TresultReactor放到TradeResult流中数据,怎么及时让FrontReactor来处理呢?(效率问题)

        int nfds = epoll_wait(m_fdEpoll, events, EPOLL_MAX_EVENTS, timeout);
    

    1、timeout设置为0

    如果handleothertask没有事做,同时socket没有IO读写事情,线程空转,浪费CPU时间片。

    2、timeout设置为10ms

    如果没有网络IO时间发生,epoll_wait需要挂起timeout时间才能返回,这样当有其他任务发生,handle_other_task()就会延时处理,TradeResultFlow交易结果流中的数据,frontReactor不能及时处理。

    解决方案:

    创建eventfd(唤醒fd),并把eventfd绑定到epollfd中,当我们想唤醒直接去执行handle_other_task()时,往eventfd中写入一个字节,该eventfd就变成可读,epoll_wait就立马返回,接下来就可以处理handle_other_task()里面的任务了。

    相关文章

      网友评论

          本文标题:多线程服务器的常见编程模型

          本文链接:https://www.haomeiwen.com/subject/ydgmyktx.html