当前位置:首页>Linux>Linux poll机制深度剖析: 从设计哲学到内核实现

Linux poll机制深度剖析: 从设计哲学到内核实现

  • 2026-01-16 01:22:41
Linux poll机制深度剖析: 从设计哲学到内核实现

Linux poll机制深度剖析: 从设计哲学到内核实现

引言: 为什么需要I/O多路复用?

想象一下这样一个场景: 你经营着一家繁忙的餐厅, 有10张桌子需要服务. 如果你采用顺序服务的方式——先为第1桌点餐、上菜、结账, 再处理第2桌, 如此循环——那么第10桌的客人可能会饿晕. 聪明的餐厅经理会采用巡视观察的方式: 在大厅里走动, 观察每桌的状态, 哪桌需要点餐、哪桌可以上菜、哪桌准备结账, 然后及时提供服务

这就是I/O多路复用的核心思想!在Linux网络编程中, 我们经常需要同时处理多个文件描述符(sockets、pipes、设备等). poll机制就是那位"巡视的餐厅经理", 它允许一个进程同时监控多个I/O通道的状态变化

第一章: poll的设计哲学与核心概念

1.1 poll vs. select: 历史演进

在深入poll之前, 我们先看看它的前身——select系统调用. select最早出现在4.2BSD Unix(1983年), 后来被移植到Linux中. 但它有几个明显的限制:

// select的原型int select(int nfds, fd_set *readfds, fd_set *writefds,           fd_set *exceptfds, struct timeval *timeout);

select的主要问题:

  1. 1. 文件描述符数量限制: 通常为1024(FD_SETSIZE)
  2. 2. 效率问题: 每次调用都需要传递所有fd集合
  3. 3. 重复初始化: 每次调用后都需要重新设置fd集合

为了解决这些问题, poll应运而生. 让我们通过一个对比表格来理解二者的差异:

特性
select
poll
最大文件描述符数
有限制(FD_SETSIZE)
理论上无限制(受内存限制)
效率
O(n), 每次线性扫描
O(n), 但数据结构更优
可移植性
POSIX标准, 广泛支持
System V起源, 但现代系统都支持
内核实现
位图操作
链表/数组操作
触发模式
水平触发(LT)
水平触发(LT)

1.2 poll的核心数据结构

poll的核心是pollfd结构体, 定义如下:

#include <poll.h>struct pollfd {    int   fd;         /* 文件描述符 */    short events;     /* 关注的事件 */    short revents;    /* 返回的事件 */};

关键字段解析:

  1. 1. fd: 要监控的文件描述符. 如果是负数, poll会忽略这个条目
  2. 2. events: 应用程序关心的事件掩码. 这是一个输入参数, 可以设置为以下标志的组合:
// 事件标志定义#define POLLIN      0x0001    /* 有数据可读 */#define POLLPRI     0x0002    /* 有紧急数据可读 */#define POLLOUT     0x0004    /* 写数据不会阻塞 */#define POLLERR     0x0008    /* 发生错误 */#define POLLHUP     0x0010    /* 连接挂起 */#define POLLNVAL    0x0020    /* 无效的请求: fd未打开 */// Linux特有扩展#define POLLRDNORM  0x0040    /* 普通数据可读 */#define POLLRDBAND  0x0080    /* 优先级带数据可读 */#define POLLWRNORM  0x0100    /* 普通数据可写 */#define POLLWRBAND  0x0200    /* 优先级带数据可写 */
  1. 3. revents: 内核返回的事件掩码. 这是一个输出参数, 表示哪些事件真正发生了

1.3 poll系统调用原型

#include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);

参数详解:

  • • fds: 指向pollfd结构体数组的指针. 就像餐厅的"桌位状态表"
  • • nfds: 数组中的元素个数. 告诉内核: "我有多少张桌子需要查看"
  • • timeout: 超时时间(毫秒). 特殊值:
    • • 0: 立即返回, 不阻塞(快速巡视)
    • • -1: 无限等待, 直到有事件发生(一直巡视直到有事做)
    • • >0: 等待指定的毫秒数(巡视一定时间后休息)

返回值:

  • • >0: 有事件发生的文件描述符数量
  • • 0: 超时, 没有事件发生
  • • -1: 发生错误, 并设置errno

第二章: 内核实现机制深度解析

2.1 poll的整体架构

让我们用Mermaid图来展示poll的核心调用流程:

2.2 关键数据结构详解

在内核中, poll的核心数据结构是poll_tablepoll_wqueues. 让我们深入探究:

// 内核中的关键数据结构typedefstruct poll_table_struct {    poll_queue_proc _qproc;    unsigned long _key;} poll_table;struct poll_wqueues {    poll_table pt;struct poll_table_page *table;struct task_struct *polling_task;    int triggered;    int error;    int inline_index;struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES];};

数据结构关系图:

2.3 poll的内核实现流程

2.3.1 系统调用入口

poll系统调用的入口在Linux内核源码fs/select.c中:

// 简化的系统调用入口SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds,                unsigned int, nfds, int, timeout_msecs){struct timespec64 end_time, *to = NULL;    int ret;    // 处理超时时间    if (timeout_msecs >= 0) {        to = &end_time;        poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC,                               NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC));    }    // 核心处理    ret = do_sys_poll(ufds, nfds, to);    // 处理可能的信号中断    if (ret == -ERESTARTNOHAND) {        // 重新启动逻辑    }    return ret;}

2.3.2 核心处理函数do_sys_poll

static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,                       struct timespec64 *end_time){struct poll_wqueues table;    int err = -EFAULT, fdcount, len;    // 分配空间存放pollfdstruct poll_list *head = NULL;struct poll_list *walk;    // 1. 从用户空间复制pollfd数组    len = min_t(unsigned int, nfds, N_STACK_PPS);    walk = head = kmalloc(sizeof(struct poll_list) +                         sizeof(struct pollfd) * len, GFP_KERNEL);    // 2. 初始化等待队列    poll_initwait(&table);    // 3. 核心轮询循环    fdcount = do_poll(head, nfds, end_time, &table);    // 4. 将结果复制回用户空间    for (walk = head; walk != NULL; walk = walk->next) {struct pollfd *fds = walk->entries;        int j;        for (j = 0; j < walk->len; j++, ufds++) {            if (__put_user(fds[j].revents, &ufds->revents))                goto out_fds;        }    }    err = fdcount;out_fds:    // 5. 清理资源    poll_freewait(&table);    // 释放内存    return err;}

2.3.3 真正的轮询引擎: do_poll

static int do_poll(struct poll_list *list, unsigned int nfds,                   struct timespec64 *end_time, struct poll_wqueues *wait){    poll_table* pt = &wait->pt;    int count = 0;    pollfdtable pfdtable = { .pollfdptr = NULL };    // 设置超时    if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {        pt->_qproc = NULL;        timeout = 0;    }    for (;;) {struct poll_list *walk;        bool can_busy_loop = false;        // 遍历所有文件描述符        for (walk = list; walk != NULL; walk = walk->next) {struct pollfd * pfd = walk->entries;            int j;            for (j = 0; j < walk->len; j++, pfd++) {                // 跳过无效的fd                if (pfd->fd < 0)                    continue;                // 检查单个fd的状态                mask = do_pollfd(pfd, pt, &can_busy_loop);                if (mask) {                    // 有事件发生                    count++;                    pt->_qproc = NULL;                }            }        }        // 如果已经找到就绪的fd或超时, 则返回        if (count || timed_out || signal_pending(current))            break;        // 如果没有找到就绪的fd, 则进入等待        if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack))            timed_out = 1;    }    return count;}

2.3.4 检查单个文件描述符: do_pollfd

static inline __poll_t do_pollfd(struct pollfd *pollfd, poll_table *pwait,                                 bool *can_busy_poll){    int fd = pollfd->fd;    __poll_t mask = 0;    if (fd >= 0) {struct fd f = fdget(fd);        if (f.file) {            conststruct file_operations *f_op;            __poll_t wait_key = pwait ? pwait->_key : 0;            // 获取文件操作结构            f_op = f.file->f_op;            // 调用文件的poll方法            mask = DEFAULT_POLLMASK;            if (f_op->poll) {                // 这里传入pwait, 驱动程序会将当前进程加入等待队列                mask = f_op->poll(f.file, pwait);                // 屏蔽掉用户不关心的事件                mask &= pollfd->events | POLLERR | POLLHUP;            }            fdput(f);        }    }    pollfd->revents = mask;    return mask;}

2.4 驱动程序的poll方法

在驱动程序中, 需要实现file_operations中的poll方法. 以下是简化的示例:

// 设备驱动的poll实现示例static unsigned int my_device_poll(struct file *filp, poll_table *wait){struct my_device *dev = filp->private_data;    unsigned int mask = 0;    // 将当前进程加入等待队列    poll_wait(filp, &dev->read_queue, wait);    poll_wait(filp, &dev->write_queue, wait);    // 检查设备状态    if (device_has_data(dev))        mask |= POLLIN | POLLRDNORM;  // 可读    if (device_can_write(dev))        mask |= POLLOUT | POLLWRNORM;  // 可写    if (device_has_error(dev))        mask |= POLLERR;  // 错误    return mask;}

第三章: poll的工作原理解析与生活比喻

3.1 生活比喻: 餐厅经理巡视模式

让我们用一个完整的餐厅比喻来理解poll的工作原理:

餐厅(内核空间)                   顾客区(用户空间)------------                    ------------经理办公室                       | 顾客1 |     |                          | 顾客2 |     v                          | 顾客3 |巡视记录表 <-------------------> | ...  |     |                          ------------     v  服务员     |     v厨房/收银台等资源

对应关系:

  • • 餐厅经理 = poll系统调用
  • • 巡视记录表 = pollfd数组
  • • 桌子状态 = 文件描述符状态
  • • 服务员 = 设备驱动
  • • 厨房/收银台 = 硬件资源

工作流程:

  1. 1. 经理(poll)拿着巡视记录表(pollfd数组)开始巡视
  2. 2. 对每张桌子(文件描述符), 经理询问服务员(驱动)当前状态
  3. 3. 如果桌子当前就有需求(数据就绪), 立即记录
  4. 4. 如果桌子暂时没需求, 经理留下联系方式(加入等待队列)后继续巡视
  5. 5. 当所有桌子巡视完后, 如果都没有立即需求, 经理回办公室等待(进程休眠)
  6. 6. 任何桌子有需求时, 服务员打电话通知经理(等待队列唤醒)
  7. 7. 经理再次巡视, 处理有需求的桌子

3.2 poll的三种工作模式

3.2.1 立即返回模式(timeout = 0)

特点: 就像经理快速在餐厅走一圈, 只看当前状态, 不等待

3.2.2 无限等待模式(timeout = -1)

3.2.3 超时等待模式(timeout > 0)

3.3 poll的唤醒机制

poll的唤醒机制是其核心魔法. 让我们看看当数据到达时发生了什么:

// 设备驱动中的数据到达处理static irqreturn_t device_interrupt(int irq, void *dev_id){struct my_device *dev = dev_id;    // 读取数据到缓冲区    read_data_from_hardware(dev);    // 唤醒等待队列    wake_up_interruptible(&dev->read_queue);    return IRQ_HANDLED;}

唤醒流程:

  1. 1. 硬件中断发生
  2. 2. 驱动处理中断, 读取数据
  3. 3. 驱动调用wake_up系列函数
  4. 4. 内核调度器重新调度等待进程
  5. 5. poll系统调用继续执行, 返回就绪的fd

第四章: poll的完整示例与代码分析

4.1 一个简单的poll服务器示例

让我们实现一个简单的echo服务器, 使用poll处理多个客户端连接:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <poll.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#define MAX_CLIENTS 1024#define BUFFER_SIZE 1024int main(int argc, char *argv[]){    int server_fd, client_fd;struct sockaddr_in server_addr, client_addr;    socklen_t client_len = sizeof(client_addr);struct pollfd fds[MAX_CLIENTS + 1];    int nfds = 1;  // 初始只有监听socket    int timeout = 5000;  // 5秒超时    char buffer[BUFFER_SIZE];    // 1. 创建服务器socket    server_fd = socket(AF_INET, SOCK_STREAM, 0);    if (server_fd < 0) {        perror("socket");        exit(EXIT_FAILURE);    }    // 2. 设置socket选项, 避免地址重用问题    int opt = 1;    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));    // 3. 绑定地址和端口    server_addr.sin_family = AF_INET;    server_addr.sin_addr.s_addr = INADDR_ANY;    server_addr.sin_port = htons(8080);    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {        perror("bind");        close(server_fd);        exit(EXIT_FAILURE);    }    // 4. 开始监听    if (listen(server_fd, 10) < 0) {        perror("listen");        close(server_fd);        exit(EXIT_FAILURE);    }    printf("Server listening on port 8080...\n");    // 5. 初始化pollfd数组    memset(fds, 0, sizeof(fds));    fds[0].fd = server_fd;    fds[0].events = POLLIN;  // 监听读事件    // 6. 主事件循环    while (1) {        int ret = poll(fds, nfds, timeout);        if (ret < 0) {            perror("poll");            break;        }        if (ret == 0) {            // 超时, 可以在这里处理定时任务            printf("poll timeout, no events.\n");            continue;        }        // 7. 检查所有文件描述符        int current_nfds = nfds;        for (int i = 0; i < current_nfds; i++) {            // 跳过没有事件的fd            if (fds[i].revents == 0)                continue;            // 8. 处理监听socket(新连接)            if (fds[i].fd == server_fd) {                client_fd = accept(server_fd,                                  (struct sockaddr*)&client_addr,                                 &client_len);                if (client_fd < 0) {                    perror("accept");                    continue;                }                printf("New connection from %s:%d\n",                       inet_ntoa(client_addr.sin_addr),                       ntohs(client_addr.sin_port));                // 添加新客户端到pollfd数组                if (nfds < MAX_CLIENTS) {                    fds[nfds].fd = client_fd;                    fds[nfds].events = POLLIN;                    nfds++;                } else {                    printf("Too many connections, closing new connection\n");                    close(client_fd);                }            }            // 9. 处理客户端socket            else {                int fd = fds[i].fd;                // 检查是否有数据可读                if (fds[i].revents & POLLIN) {                    ssize_t bytes_read = read(fd, buffer, BUFFER_SIZE - 1);                    if (bytes_read <= 0) {                        // 连接关闭或错误                        printf("Client disconnected\n");                        close(fd);                        // 从数组中移除                        fds[i].fd = -1;  // poll会忽略负数的fd                    } else {                        // 处理数据(简单echo)                        buffer[bytes_read] = '\0';                        printf("Received: %s", buffer);                        // 回显数据                        write(fd, buffer, bytes_read);                    }                }                // 检查其他事件                if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {                    printf("Error on client socket, closing\n");                    close(fd);                    fds[i].fd = -1;                }            }        }        // 10. 压缩数组, 移除已关闭的fd        int j = 0;        for (int i = 0; i < nfds; i++) {            if (fds[i].fd != -1) {                if (i != j) {                    fds[j] = fds[i];                }                j++;            }        }        nfds = j;    }    // 清理    for (int i = 0; i < nfds; i++) {        if (fds[i].fd >= 0)            close(fds[i].fd);    }    return 0;}

4.2 代码解析与关键点

关键设计模式:

  1. 1. 数组管理技巧:
    • • 使用fd = -1标记无效的fd
    • • 定期压缩数组, 避免空洞
  2. 2. 事件处理顺序:
    • • 先处理监听socket(新连接)
    • • 再处理客户端socket(数据)
  3. 3. 错误处理:
    • • 检查所有可能的事件: POLLERR | POLLHUP | POLLNVAL
    • • 正确处理read返回0(连接关闭)

第五章: 性能分析与优化策略

5.1 poll的性能特点

让我们通过一个性能对比表来理解poll的优缺点:

特性
poll
select
epoll (对比参考)
时间复杂度
O(n)
O(n)
O(1)就绪fd
内存使用
每个fd 8字节
位图(每个fd 1位)
内核维护红黑树
最大fd数
受RLIMIT_NOFILE限制
FD_SETSIZE(通常1024)
系统内存限制
内核到用户空间
复制整个数组
复制整个位图
只复制就绪事件
触发模式
LT(水平触发)
LT(水平触发)
LT/ET可选
适用场景
fd数较少(<1000)
兼容性要求高
高并发、大量连接

5.2 poll的性能瓶颈

主要瓶颈:

  1. 1. 内存复制开销: 每次调用都需要在用户空间和内核空间之间复制整个pollfd数组
  2. 2. 线性扫描开销: 即使只有一个fd就绪, 也需要扫描所有fd
  3. 3. 系统调用开销: 每次poll都是完整的系统调用

5.3 优化策略

5.3.1 减少poll调用频率

// 优化前: 固定超时while (1) {    ret = poll(fds, nfds, 100);  // 总是等待100ms    // 处理事件}// 优化后: 动态超时while (1) {    int timeout = calculate_dynamic_timeout();    ret = poll(fds, nfds, timeout);    if (ret == 0) {        // 超时, 处理后台任务        handle_background_tasks();        continue;    }    // 处理事件}

5.3.2 使用pollfd数组池

// 避免频繁分配/释放内存#define POOL_SIZE 1024staticstruct pollfd fd_pool[POOL_SIZE];static int fd_pool_used = 0;// 从池中获取pollfdstruct pollfd *get_pollfd(int fd, short events) {    if (fd_pool_used >= POOL_SIZE)        return NULL;struct pollfd *pfd = &fd_pool[fd_pool_used++];    pfd->fd = fd;    pfd->events = events;    pfd->revents = 0;    return pfd;}// 重置池void reset_pollfd_pool() {    for (int i = 0; i < fd_pool_used; i++) {        fd_pool[i].fd = -1;    }    fd_pool_used = 0;}

5.3.3 事件驱动架构优化

第六章: 调试与监控工具

6.1 使用strace跟踪poll调用

# 跟踪poll系统调用strace -e poll -f ./poll_server# 输出示例# [pid 12345] poll([{fd=3, events=POLLIN}, {fd=4, events=POLLIN}], 2, 5000) = 1# [pid 12345] poll([{fd=3, events=POLLIN}, {fd=4, events=POLLIN}], 2, 5000) = 0# [pid 12345] poll([{fd=3, events=POLLIN}, {fd=4, events=POLLIN}], 2, 5000) = 2

6.2 使用perf分析poll性能

# 记录性能数据perf record -e syscalls:sys_enter_poll,syscalls:sys_exit_poll -ag# 生成报告perf report# 查看调用图perf report --stdio --no-children

6.3 监控文件描述符状态

# 查看进程打开的文件描述符ls -l /proc/<pid>/fd/# 查看特定fd的详细信息cat /proc/<pid>/fdinfo/3# 查看poll等待队列cat /proc/<pid>/waitstatus

6.4 自定义调试输出

在驱动程序中添加调试信息:

// 带调试的poll实现static unsigned int my_device_poll(struct file *filp, poll_table *wait){struct my_device *dev = filp->private_data;    unsigned int mask = 0;    printk(KERN_DEBUG "my_device_poll called, adding to wait queue\n");    poll_wait(filp, &dev->read_queue, wait);    if (device_has_data(dev)) {        printk(KERN_DEBUG "my_device_poll: data available\n");        mask |= POLLIN | POLLRDNORM;    }    printk(KERN_DEBUG "my_device_poll returning mask: 0x%x\n", mask);    return mask;}

第七章: poll在实际系统中的应用

7.1 在开源软件中的应用

7.1.1 BusyBox中的poll应用

BusyBox是一个集成了许多Unix工具的软件, 广泛使用poll:

// BusyBox中telnetd的poll使用static void handle_connections(int listen_fd){struct pollfd pfds[2];    pfds[0].fd = listen_fd;    pfds[0].events = POLLIN;    while (1) {        int ret = poll(pfds, 1, -1);        if (ret > 0 && (pfds[0].revents & POLLIN)) {            int conn_fd = accept(listen_fd, NULL, NULL);            handle_session(conn_fd);        }    }}

7.1.2 Redis中的poll使用

Redis在部分平台上使用poll作为后备的I/O多路复用机制:

// Redis的ae_select.c中static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {    aeApiState *state = eventLoop->apidata;    int retval, j, numevents = 0;    memcpy(state->events, state->events_source, sizeof(struct pollfd)*eventLoop->setsize);    retval = poll(state->events,eventLoop->setsize,                  tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);    if (retval > 0) {        for (j = 0; j <= eventLoop->setsize; j++) {            int mask = 0;struct pollfd *pfd = &state->events[j];            if (pfd->revents & POLLIN) mask |= AE_READABLE;            if (pfd->revents & POLLOUT) mask |= AE_WRITABLE;            if (pfd->revents & POLLERR) mask |= AE_WRITABLE|AE_READABLE;            if (pfd->revents & POLLHUP) mask |= AE_WRITABLE|AE_READABLE;            eventLoop->fired[numevents].fd = pfd->fd;            eventLoop->fired[numevents].mask = mask;            numevents++;        }    }    return numevents;}

7.2 poll在嵌入式系统中的应用

在资源受限的嵌入式系统中, poll因其简单性和低内存开销而被广泛使用:

// 嵌入式系统中的多设备监控struct pollfd device_fds[MAX_DEVICES];void embedded_main_loop(void){    // 初始化各种设备    device_fds[0].fd = open_uart_device("/dev/ttyS0");    device_fds[0].events = POLLIN;    device_fds[1].fd = open_gpio_device("/dev/gpio");    device_fds[1].events = POLLPRI;  // 用于边缘触发    device_fds[2].fd = open_sensor_device("/dev/sensor");    device_fds[2].events = POLLIN;    // 主事件循环    while (!system_shutdown) {        int ret = poll(device_fds, 3, 100);  // 100ms超时        if (ret > 0) {            // 处理UART数据            if (device_fds[0].revents & POLLIN) {                handle_uart_data(device_fds[0].fd);            }            // 处理GPIO中断            if (device_fds[1].revents & POLLPRI) {                handle_gpio_interrupt(device_fds[1].fd);            }            // 处理传感器数据            if (device_fds[2].revents & POLLIN) {                handle_sensor_data(device_fds[2].fd);            }        }        // 空闲时处理低优先级任务        if (ret == 0) {            handle_low_priority_tasks();        }    }}

第八章: 与epoll的对比与迁移指南

8.1 poll vs. epoll 详细对比

维度
poll
epoll
核心数据结构
用户空间数组
内核红黑树+就绪链表
时间复杂度
O(n)
O(1)就绪事件处理
内存复制
每次复制整个数组
共享内存(mmap)
最大连接数
受进程fd限制
系统内存限制
事件触发
水平触发(LT)
LT/ET可选
编程复杂度
简单
中等
适用场景
<1000连接, 跨平台
高并发(>1000连接)
内核支持
所有Unix-like系统
Linux特有(2.6+)

8.2 从poll迁移到epoll的指南

8.2.1 基本迁移步骤

// poll风格struct pollfd fds[MAX_EVENTS];int nfds = 0;// 添加fdfds[nfds].fd = socket_fd;fds[nfds].events = POLLIN | POLLOUT;nfds++;// 事件循环while (1) {    ret = poll(fds, nfds, timeout);    for (i = 0; i < nfds; i++) {        if (fds[i].revents & POLLIN) {            // 处理读事件        }    }}// --------------------------------------------------// epoll风格int epoll_fd = epoll_create1(0);struct epoll_event ev, events[MAX_EVENTS];// 添加fdev.events = EPOLLIN | EPOLLOUT;  // 注意: 标志名前缀不同ev.data.fd = socket_fd;epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &ev);// 事件循环while (1) {    int n = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout);    for (i = 0; i < n; i++) {        if (events[i].events & EPOLLIN) {            // 处理读事件        }    }}

8.2.2 事件标志映射表

poll事件
epoll事件
说明
POLLIN
EPOLLIN
数据可读
POLLOUT
EPOLLOUT
数据可写
POLLPRI
EPOLLPRI
紧急数据可读
POLLERR
EPOLLERR
错误发生
POLLHUP
EPOLLHUP
连接挂起
POLLRDHUP
EPOLLRDHUP
对端关闭连接
-
EPOLLET
边缘触发模式(poll没有对应项)
-
EPOLLONESHOT
单次事件(poll没有对应项)

8.3 何时选择poll而非epoll

尽管epoll在性能上有优势, 但poll仍然有它的用武之地:

  1. 1. 跨平台需求: 需要支持非Linux系统
  2. 2. 简单应用: 连接数少(<100), 性能差异不明显
  3. 3. 嵌入式系统: 内核版本较旧, 不支持epoll
  4. 4. 原型开发: 快速验证想法, 后期再优化
  5. 5. 特殊场景: 需要同时监控设备文件和网络socket

第九章: 高级主题与最佳实践

9.1 poll与信号处理的交互

poll系统调用可能会被信号中断, 正确处理信号很重要:

// 正确处理EINTR错误while (1) {    ret = poll(fds, nfds, timeout);    if (ret == -1) {        if (errno == EINTR) {            // 被信号中断, 检查全局标志            if (should_exit)                break;            // 否则重新poll            continue;        } else {            // 真正的错误            perror("poll");            break;        }    }    // 正常处理事件    handle_events(fds, nfds);}

9.2 poll在多线程环境中的使用

// 线程安全的poll使用模式pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;void* poll_thread(void* arg){struct pollfd local_fds[MAX_FDS];    int local_nfds;    while (!shutdown_requested) {        // 1. 复制fd数组(加锁)        pthread_mutex_lock(&fd_mutex);        memcpy(local_fds, global_fds, sizeof(struct pollfd) * global_nfds);        local_nfds = global_nfds;        pthread_mutex_unlock(&fd_mutex);        // 2. 执行poll(不加锁)        int ret = poll(local_fds, local_nfds, 100);        // 3. 处理事件        if (ret > 0) {            for (int i = 0; i < local_nfds; i++) {                if (local_fds[i].revents) {                    handle_event_safely(local_fds[i].fd, local_fds[i].revents);                }            }        }    }    return NULL;}

9.3 poll的性能调优参数

Linux内核提供了一些参数可以调整poll的行为:

# 查看当前系统的poll相关参数sysctl -a | grep poll# 常见的调优参数# /proc/sys/fs/epoll/max_user_watches  # 最大监控fd数# /proc/sys/fs/epoll/max_user_instances # 最大epoll实例数# 调整参数(需要root权限)echo 65536 > /proc/sys/fs/epoll/max_user_watches

第十章: 总结与展望

10.1 poll的核心价值总结

通过全文的分析, 我们可以总结出poll机制的几个核心价值:

  1. 1. 简单性: API简单直观, 易于理解和使用
  2. 2. 可移植性: 几乎在所有Unix-like系统上都可用
  3. 3. 资源效率: 对于少量连接, 内存和CPU使用都很高效
  4. 4. 灵活性: 可以监控任何类型的文件描述符

10.2 poll的技术演进路线图

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-02-09 00:44:22 HTTP/2.0 GET : https://f.mffb.com.cn/a/460607.html
  2. 运行时间 : 0.120014s [ 吞吐率:8.33req/s ] 内存消耗:5,177.64kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=acfcfa982264b708c5d72b74a1a7be9d
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001058s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001658s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000801s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000658s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001515s ]
  6. SELECT * FROM `set` [ RunTime:0.000586s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001613s ]
  8. SELECT * FROM `article` WHERE `id` = 460607 LIMIT 1 [ RunTime:0.001335s ]
  9. UPDATE `article` SET `lasttime` = 1770569062 WHERE `id` = 460607 [ RunTime:0.003640s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000599s ]
  11. SELECT * FROM `article` WHERE `id` < 460607 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001069s ]
  12. SELECT * FROM `article` WHERE `id` > 460607 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001048s ]
  13. SELECT * FROM `article` WHERE `id` < 460607 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.005593s ]
  14. SELECT * FROM `article` WHERE `id` < 460607 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002081s ]
  15. SELECT * FROM `article` WHERE `id` < 460607 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.004582s ]
0.123921s