当前位置:首页>Linux>Linux 并发编程全解析:从线程同步到 I/O 多路复用

Linux 并发编程全解析:从线程同步到 I/O 多路复用

  • 2026-08-21 07:53:38
Linux 并发编程全解析:从线程同步到 I/O 多路复用

线程

一、线程基础

1.1 线程是什么?

  • 「进程」:操作系统分配资源(内存空间、文件描述符、信号表...)的最小单位。
  • 「线程」:操作系统「调度执行」的最小单位。同一进程的多个线程共享:
    • 虚拟内存、代码段、数据段、堆
    • 文件描述符表、信号处理、工作目录、用户/组 id
    • 但每个线程「独立拥有」:线程 id、栈、寄存器、信号掩码、errno、线程私有数据(pthread_key

直观对比:

项目
多进程
多线程
资源共享
独立的地址空间,天然隔离
共享地址空间,天然共享内存
上下文切换
更重(切换页表、刷新 TLB、刷新 caches 的概率大)
较轻(共享页表)
通信方式
复杂:管道、FIFO、mmap、socket、信号
天然的共享内存 + 同步原语
可靠性
一个进程 crash 不影响其他进程
一个线程 crash 通常会把整个进程带走
安全边界
强隔离,不易误操作
强耦合,需要严格同步

1.2 基本 lifecycle

#include<pthread.h>#include<stdio.h>#include<unistd.h>// 推荐用法:函数指针写法staticvoid *worker(void *arg){int id = *(int *)arg;printf("thread %d start\n", id);    usleep(100 * 1000);printf("thread %d end\n", id);// 方式一:返回值;主线程通过 pthread_join 获取// 注意:只能返回永存的值;静态、malloc 或 (void*)(long)staticint ret = 42;return (void *)(long)ret;}intmain(void){pthread_t tid;int id = 1;// 创建线程    pthread_create(&tid, NULL, worker, &id);// 回收线程void *ret = NULL;    pthread_join(tid, &ret);printf("thread returned %ld\n", (long)ret);return0;}

几个易踩坑的点:

  • arg 的生命周期必须长于线程。不要传栈地址给不 join 的线程,除非你保证栈还在。
  • pthread_join 会阻塞等待指定线程结束;不调用会变成 「"zombie 线程"」,资源和 PID 不回收。
  • pthread_detach 告诉系统"我不管这个线程了,它结束就自动回收"。例如:pthread_detach(pthread_self)
  • 线程函数里不要做 return &main_stack_value,应该 malloc 一个、或返回全局/静态变量、或强转 (void*)(long)

1.3 线程的数据类型

作用
类型
线程句柄
pthread_t
一次性初始化控制
pthread_once_t
(常 PTHREAD_ONCE_INIT
互斥锁
pthread_mutex_t
读写锁
pthread_rwlock_t
条件变量
pthread_cond_t
自旋锁
pthread_spinlock_t
线程私有键
pthread_key_t
信号量
sem_t
<semaphore.h>
栅栏
pthread_barrier_t

1.4 Cancel 与 Cleanup

// 主线程中取消子线程pthread_cancel(tid);// 子线程定义清理动作(被 cancel 时自动调用)// push / pop 必须是配对出现在同一函数、同一大括号的"宏"pthread_cleanup_push(cleanup_handler, arg);// ...pthread_cleanup_pop(execute);       // 0: 只弹出; 非 0: 调用 handler

Cancel 实际上是"请求",不是强制。默认是 「deferred cancel」:只在遇到取消点函数(readwritepthread_cond_waitsleepsem_wait...)时才退出。可以用 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) 改为异步,但「容易在持有锁时被杀死」,导致后续所有阻塞在该锁上的线程永久卡住。

工程实践里我更偏爱"主动退出"替代 cancel:让线程轮询一个 atomic flag,看到就主动退出、统一走清理逻辑。这样可以避免异步 cancel 的资源泄漏和锁遗留问题。

二、同步原语(Synchronization Primitives)

2.1 为什么需要同步

共享内存天生可见,但「可见性、原子性、顺序性」三个问题会导致:

  • 「竞态」(race condition):两个线程同时读写同一变量,典型如 counter++
  • 「数据撕裂」(torn read/write):写操作被中断,对方读到一半旧一半新
  • 「编译器重排」:优化后实际执行顺序不一定是你写的顺序
  • 「CPU 重排」:弱内存序架构(ARM/Power)上观察到的顺序和你写的完全不同

C11 stdatomic.h、C23 atomic、GCC __atomic_* / __sync_* 都能帮你解决可见性 + 原子 + memory-order 问题。但在"同步原语"这个话题里,我们通常把"互斥锁 / 条件变量 / 读写锁 / 信号量 / 自旋锁 / 栅栏"这些负责"协调与等待"的机制称作同步原语。

2.2 互斥锁 pthread_mutex_t

// 静态初始化(PTHREAD_MUTEX_INITIALIZER)staticpthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;// 或者运行时初始化(推荐用于动态分配的锁 / 需要设置属性的锁)pthread_mutexattr_t attr;pthread_mutexattr_init(&attr);pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); // 或 RECURSIVE / NORMALpthread_mutex_init(&mtx, &attr);pthread_mutexattr_destroy(&attr);pthread_mutex_lock(&mtx);// 临界区pthread_mutex_unlock(&mtx);// 用完销毁pthread_mutex_destroy(&mtx);

典型模式:

staticpthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;staticint counter = 0;intinc(void){    pthread_mutex_lock(&mtx);int new_val = ++counter;                // 锁住 Read-Modify-Write    pthread_mutex_unlock(&mtx);return new_val;}// 易错点:在锁外直接读 counter 拿到的可能是过期值;只在锁内保证可见性

类型:

  • PTHREAD_MUTEX_NORMAL:非递归锁,同线程加锁两次立刻死锁
  • PTHREAD_MUTEX_RECURSIVE:递归锁,支持同一线程重复加锁(内部维护锁计数 + owner)
  • PTHREAD_MUTEX_ERRORCHECK:加锁两次立刻返回 EDEADLK,项目 debug 期首选

适用场景:

  • 临界区短、争用低:直接 mutex 是最稳的选择
  • 临界区长、争用高、并发读远大于写:考虑读写锁

2.3 读写锁 pthread_rwlock_t

staticpthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER;// 读锁:多个线程可以同时持有pthread_rwlock_rdlock(&rw);/* 读共享数据 */pthread_rwlock_unlock(&rw);// 写锁:独占pthread_rwlock_wrlock(&rw);/* 修改共享数据 */pthread_rwlock_unlock(&rw);

适用场景:读 >> 写,例如「缓存表」「路由表」「全局 lookup 表」

缺点:

  • 「写饥饿」:很多实现偏向读锁,如果读线程一直涌来,写线程可能长期得不到锁
  • 成本:实现比 mutex 更复杂,「在短临界区或 write 频繁的场景,反而比 mutex 慢」

工程建议:先上 mutex,性能出现瓶颈且 profiling 证实是读争用主导,再改用读写锁。

2.4 条件变量 pthread_cond_t

条件变量「没有状态」,它只做一件事:「让线程等待,直到另一个线程通知它"条件可能变了"」

staticpthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;staticpthread_cond_t  cond = PTHREAD_COND_INITIALIZER;staticint done = 0;// 等待者pthread_mutex_lock(&mtx);while (!done) {                          // 必须是 while:避免虚假唤醒    pthread_cond_wait(&cond, &mtx);      // 解锁并睡;醒来前重新加锁}/* 这时可以安全地访问 done 和共享数据 */pthread_mutex_unlock(&mtx);// 通知者pthread_mutex_lock(&mtx);done = 1;pthread_cond_broadcast(&cond);           // 唤醒所有等待者// 或: pthread_cond_signal(&cond);      // 唤醒一个等待者pthread_mutex_unlock(&mtx);

要点:

  • while(!cond) 不是 if(!cond):避免「虚假唤醒」(spurious wake-up)和「信号被偷吃」(偷跑线程在 signal 之后一把抢到锁)
  • pthread_cond_wait 会把提供的 mutex 「解锁+挂起」,归来时「重新带着锁」
  • signal vs broadcast
    • signal:唤醒一个等待者;适合多消费者等一个资源
    • broadcast:唤醒所有;适合等待"任务队列非空"的 worker 池

2.5 信号量 sem_t

更泛化的同步原语:有 N 个 permits,sem_wait 申请一个,sem_post 释放一个。

  • 可以当互斥锁用:sem_init(&sem, 0, 1)
  • 也可以当条件变量用:配合 mutex 表示"事件计数"
  • 特别契合生产者-消费者;最大好处是「没有 owner 概念」,任何线程都能 post
sem_t sem;sem_init(&sem, 00);            // pshared=0 表示线程间共享;value=0 表示初始没有资源// 生产sem_post(&sem);// 消费(阻塞直到有资源)sem_wait(&sem);

2.6 自旋锁 pthread_spinlock_t

pthread_spinlock_t spin;pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE);pthread_spin_lock(&spin);/* 临界区极短 */pthread_spin_unlock(&spin);pthread_spin_destroy(&spin);

和 mutex 的区别:mutex 会 syscall futex、阻塞唤醒让出 CPU;spinlock 只在用户态 CAS / lock cmpxchg 循环空转。

适用场景:

  • 临界区「极短」(几行、小于几十个 CPU 指令)
  • 不舍得付出「上下文切换的开销」(通常 1-10us)
  • 「单核慎用」:等待者占住 CPU,持有者反而得不到调度

2.7 栅栏 pthread_barrier_t

让一组线程「都到达某一阶段后一起出发」,典型的分阶段算法 / 多线程 benchmark。

pthread_barrier_t barrier;pthread_barrier_init(&barrier, NULL, N); // 需要 N 个线程到达// 在所有 worker 的阶段交界处pthread_barrier_wait(&barrier);

例如 map-reduce:N 个 map worker 把数据分片并行处理,到 reduce 阶段必须等所有 map 完成。

2.8 一次性初始化 pthread_once

staticpthread_once_t once = PTHREAD_ONCE_INIT;staticstructconfig *global_cfg;staticvoidinit_cfg(void){ global_cfg = load_config("/etc/app.conf"); }struct config *get_cfg(void){    pthread_once(&once, init_cfg);return global_cfg;}

等价于 C11 的 call_once,非常适合全局单例的"懒初始化"。

2.9 避免 deadlock 的铁律

  • 「固定的全局加锁顺序」:所有线程以相同顺序加 A->B->C 锁;反过来会死锁
  • 「设置超时」pthread_mutex_timedlocksem_timedwait
  • 「用 lock hierarchy」:把锁编号,文档 + 代码层面保持一致
  • 「优先使用细粒度锁 / 减少持锁时长」
  • 「避免在持锁时调用外部代码」(可能触发新的加锁)
  • 「静态分析工具」helgrind / TSan 能检测数据竞争与死锁

三、三个经典问题(面试"三件套")

3.1 生产者-消费者(Bounded Buffer)

#define N 16staticint buffer[N];staticint head = 0, tail = 0, count = 0;staticpthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;staticpthread_cond_t not_full  = PTHREAD_COND_INITIALIZER;staticpthread_cond_t not_empty = PTHREAD_COND_INITIALIZER;voidproduce(int value){    pthread_mutex_lock(&mtx);while (count == N) pthread_cond_wait(&not_full, &mtx);   // 满则等待    buffer[head] = value;    head = (head + 1) % N;    count++;    pthread_cond_signal(&not_empty);                         // 通知消费者    pthread_mutex_unlock(&mtx);}intconsume(void){    pthread_mutex_lock(&mtx);while (count == 0) pthread_cond_wait(&not_empty, &mtx);int v = buffer[tail];    tail = (tail + 1) % N;    count--;    pthread_cond_signal(&not_full);    pthread_mutex_unlock(&mtx);return v;}

要点:

  • 锁保护「判断」「入队/出队」,保护判定和状态修改的原子性
  • while 而非 if:防止虚假唤醒和信号被偷吃
  • 每个条件变量绑定对应的「状态含义」not_full=有空间,not_empty=有数据

3.2 读者-写者

// 读者优先版staticpthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;staticpthread_cond_t  write_ok = PTHREAD_COND_INITIALIZER;staticint readers_active = 0;staticint writer_waiting = 0;staticint writers_active = 0;voidread_lock(void){    pthread_mutex_lock(&mtx);while (writers_active || writer_waiting)        pthread_cond_wait(&write_ok, &mtx);    readers_active++;    pthread_mutex_unlock(&mtx);}voidwrite_lock(void){    pthread_mutex_lock(&mtx);    writer_waiting++;while (readers_active || writers_active)        pthread_cond_wait(&write_ok, &mtx);    writer_waiting--;    writers_active = 1;    pthread_mutex_unlock(&mtx);}voidread_unlock(void){    pthread_mutex_lock(&mtx);    readers_active--;if (readers_active == 0) pthread_cond_broadcast(&write_ok);    pthread_mutex_unlock(&mtx);}voidwrite_unlock(void){    pthread_mutex_lock(&mtx);    writers_active = 0;    pthread_cond_broadcast(&write_ok);    pthread_mutex_unlock(&mtx);}

可以改造为"写者优先"或"公平版":核心差异在于 「reads_active 和 writes_active 上的等待策略」

3.3 哲学家就餐

#define P 5staticpthread_mutex_t chopsticks[P];voidphilosopher(int i){int l = i, r = (i + 1) % P;// 打破死锁的方法之一:统一先拿较小编号的筷子if (l > r) { int tmp = l; l = r; r = tmp; }    pthread_mutex_lock(&chopsticks[l]);    pthread_mutex_lock(&chopsticks[r]);    eat();    pthread_mutex_unlock(&chopsticks[r]);    pthread_mutex_unlock(&chopsticks[l]);}

其他常见解法:资源分级、仲裁者(master 限制 N-1 人同时拿筷子)、奇偶侧策略。

四、服务器场景下的线程与同步

4.1 服务器架构的演化脉络

blocking I/O + one-thread-per-connection (PREFORK)        |  成千上万连接时上下文切换爆炸,栈内存放大        vmulti-process: prefork (Apache httpd)        |  进程重量大,共享内存麻烦        vI/O multiplexing + single-threaded loop (Redis / Nginx 简化版)        |  CPU 密集型处理阻塞 loop,不友好超线程        vI/O multiplexing + thread pool (主流现代方案)        |        vio_uring + io_workqueue  (较新路线,更快但生态年轻)

4.2 模式对比

架构
优点
缺点
典型场景
阻塞 + 每连接一线程
编码直白、顺序思维
线程数爆炸;10k conns 困难
少量连接 + 单连接处理较重
线程池 + Reactor 分发
线程数可控,拥抱多核
任务拆分要仔细;临界区较多
「主流 Web / RPC」
单线程事件驱动
少锁、高吞吐 I/O
CPU 密集任务会卡 loop
Redis、memcached、DNS
epoll/Reactor + 线程池
兼具两者优点
结构较复杂
现代高性能服务器
io_uring ring
极简异步、少 syscall
Linux 5.1+ 较新,生态年轻
高性能存储 / proxy

4.3 为什么服务器场景必须考虑同步

典型模块
推荐的同步机制
全局统计(qps、活跃连接)
小规模 atomic / 短锁
连接表 lookup
rwlock 或 分段锁
写日志
mutex 或 lock-free ring
配置热加载
RCU / rwlock + once
任务队列、资源池
经典 prod-cons
Timer heap
mutex + cond 或 短 spinlock
全局资源(连接池、worker 池)
合适的组合

4.4 经典"主线程 accept + 工作线程处理"

#include<pthread.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<netinet/in.h>#include<sys/socket.h>#define PORT 8080#define THREADS 4staticint listen_fd;staticpthread_t workers[THREADS];staticvoid *worker(void *arg){    (void)arg;for (;;) {// accept 在单 listen_fd 上是线程安全的(kernel 内会串行化并避免 thundering-herd)int fd = accept(listen_fd, NULLNULL);if (fd < 0continue;char buf[4096];ssize_t n;while ((n = read(fd, buf, sizeof(buf))) > 0) {            write(fd, buf, n); // echo        }        close(fd);    }returnNULL;}intmain(void){    listen_fd = socket(AF_INET, SOCK_STREAM, 0);int opt = 1;    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));structsockaddr_ina = {        .sin_family = AF_INET,        .sin_port = htons(PORT),        .sin_addr.s_addr = htonl(INADDR_ANY),    };    bind(listen_fd, (struct sockaddr *)&a, sizeof(a));    listen(listen_fd, 128);for (int i = 0; i < THREADS; i++)        pthread_create(&workers[i], NULL, worker, NULL);for (int i = 0; i < THREADS; i++)        pthread_join(workers[i], NULL);}

这个模式有两个明显瓶颈:

  1. 突发流量:某个 Worker 被「长连接或慢连接」 block,其他 Worker 闲置——线程模型对「长尾不均」非常敏感。
  2. 高并发下 kernel 内 listen_lock 争用:accept() 本身有 listen 锁,高接受率时成为热点(可引入 SO_REUSEPORT 多 listen socket 分摊)。

可改进的方向:

  • SO_REUSEPORT 让多个线程各自 listen 自己的 socket 分摊 accept
  • epoll + non-blocking + edge-triggered 替代阻塞模型
  • 结合 eventfd + 派发队列实现 「Reactor + worker pool」

4.5 epoll + eventfd + worker pool(较高级的现代骨架)

                        main thread (Reactor)┌──────────────────────────────────────────────────────────────────────┐│  epoll_wait(listen_fd, clientfd*, eventfd, timerfd, signalfd...)    ││     │ new conn      : accept -> epoll_add                           ││     │ client ready  : read request -> task_enqueue(worker_pool)     ││     │ timerfd fired : run scheduled tasks                           ││     │ eventfd       : worker 上报完成,主线程集中 epoll_mod OUT     │└──────────────────────────────────────────────────────────────────────┘                              |                              v  task queue + broadcast/eventfd┌──────────────────────────────────────────────────────────────────────┐│                    worker threads (business logic)                   ││  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐              ││  │ worker 0 │ │ worker 1 │ │ worker 2 │ │ worker 3 │ ...          ││  └──────────┘ └──────────┘ └──────────┘ └──────────┘              │└──────────────────────────────────────────────────────────────────────┘

这样拆分后:

  • Reactor 只负责「I/O + 事件调度」,不被 CPU 密集任务卡住
  • Worker 只负责「业务逻辑」,可与 CPU 核心数线性扩展
  • 临界区只在跨线程队列上(经典的 prod-cons)

这是经典的 「Leader/Followers + Reactor」 组合,也是很多真实系统的骨干。

五、I/O 多路复用:select / poll / epoll

5.1 为什么需要多路复用

普通阻塞模型下一个线程只能处理一个 fd;要做到"一个线程管理多个 fd",只有三条路:

  • 开 N 个线程(C10K 场景开销爆炸)
  • 非阻塞 + 主动轮询(空转 CPU 浪费)
  • 「请操作系统在任意 fd 就绪时通知你」 → 多路复用

典型三段式:「注册兴趣 fd」 → 「阻塞等待任意就绪」 → 「迭代就绪集并处理」

维度
select
poll
epoll
最大 fd 数
FD_SETSIZE
,通常 1024
无限制
无限制
增长能力
每次重置 fd_set,O(n) 扫描
O(n) 扫描整个数组
O(1)(红黑树 + 就绪链表)
适用量级
< 100 fd
< 1000 fd
「≥ 1000 fd,主流」
触发模式
仅 Level Triggered
仅 Level Triggered
LT + Edge Triggered
跨平台
POSIX 通用
Linux only

5.2 select() 快速上手

#include<sys/select.h>#include<unistd.h>#include<stdio.h>intmain(void){    fd_set rfds;while (1) {        FD_ZERO(&rfds);        FD_SET(STDIN_FILENO, &rfds);structtimevaltv = { .tv_sec = 5, .tv_usec = 0 };int ret = select(STDIN_FILENO + 1, &rfds, NULLNULL, &tv);if (ret < 0) { perror("select"); break; }if (ret == 0) { printf("timeout\n"); continue; }if (FD_ISSET(STDIN_FILENO, &rfds)) {char buf[256];ssize_t n = read(STDIN_FILENO, buf, sizeof(buf));printf("got %zd bytes\n", n);        }    }return0;}

5.3 poll()——只是稍微好了点

#include<poll.h>#include<stdio.h>#include<unistd.h>intmain(void){structpollfdfds[2] = {        { .fd = STDIN_FILENO, .events = POLLIN },        { .fd = sock_fd,      .events = POLLIN },    };while (1) {int ret = poll(fds, 25000);       // 5 秒超时if (ret > 0) {for (int i = 0; i < 2; i++) {if (fds[i].revents & POLLIN) {char buf[256];ssize_t n = read(fds[i].fd, buf, sizeof(buf));printf("[%d] got %zd bytes\n", fds[i].fd, n);                }            }        }    }}

poll 没有 1024 限制,但仍是线性扫描。数千 fd 时已经吃力,数万 fd 后 O(n) 让吞吐量雪崩。

5.4 epoll——Linux 下的"主流王"

#include<sys/epoll.h>#include<unistd.h>#include<stdio.h>#define MAX_EVENTS 1024intmain(void){int epfd = epoll_create1(EPOLL_CLOEXEC);if (epfd < 0) { perror("epoll_create1"); return1; }structepoll_eventev = {        .events = EPOLLIN,                             // 默认 LT;加 EPOLLET 切换到 edge        .data.fd = STDIN_FILENO,    };    epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev);structepoll_eventevents[MAX_EVENTS];while (1) {int n = epoll_wait(epfd, events, MAX_EVENTS, -1);for (int i = 0; i < n; i++) {int fd = events[i].data.fd;if (events[i].events & (EPOLLERR | EPOLLHUP)) {                close(fd); continue;            }char buf[4096];ssize_t len;while ((len = read(fd, buf, sizeof(buf))) > 0) {printf("got %zd bytes\n", len);            }        }    }    close(epfd);return0;}

5.5 LT vs ET

触发模式
含义
优点
缺点
Level Triggered (LT)
只要处于可读/可写状态,epoll_wait 就一直报告默认行为
不容易丢事件;读不完留着下次再读;简单稳健
每次就绪都报告,唤醒次数多
Edge Triggered (ET)
「状态从未就绪→就绪时」
才报告一次
唤醒次数更少,吞吐更高
必须一次「读/写到 EAGAIN」;否则后续事件消失;必须搭配 non-blocking

经验:默认用 LT。当你已经做到以下三点时再切 ET:

  1. fd 全部设为 O_NONBLOCK
  2. while(read/write) 直到 EAGAIN
  3. 能用 EPOLLONESHOT 的多线程安全共享

5.6 epoll 经典使用场景

场景 1:聊天室 / websocket bridge

单线程 epoll 主循环负责「读写 + 广播」;CPU 密集任务(json、cpu 编码)走 worker pool。主循环之内没有锁,天然清爽。

场景 2:反向代理 / VPN 转发

clientfd 与 upstreamfd 分别注册 epoll,在「双向就绪驱动」下做数据搬运:

[ clientfd readable ] -> write to upstreamfd[ upstreamfd readable ] -> write to clientfd

epoll 天然支撑**"代理服务" = 双向就绪驱动**。

场景 3:数据库 / KV 客户端

  • MySQL client / libpq 都支持 non-blocking
  • Redis、memcached、leveldb、rocksdb 的 NIO 客户端几乎都基于 epoll 驱动

场景 4:混合事件源(都是 fd)

把 eventfd(跨线程通知)、timerfd(高精度定时)、signalfd(把信号变成 fd 事件)也挂在 epoll 下,就能形成「统一事件驱动的异步主循环」

// listen_fd, client_fds, eventfd, timerfd, signalfd 全部走同一个 epoll_wait

这是高性能服务器"少锁、多核、多连接"的关键魔法之一。

5.7 select / poll / epoll 选型建议

  • < 100 fd、跨平台刚需:select
  • < 1000 fd、不想绑定 Linux:poll
  • Linux 高并发:epoll(默认选择)
  • 想尝鲜 + Linux 5.1+:io_uring
  • 现代 C++ / Rust:直接用 libeventlibevlibuvboost.asio(它们内部也是 select / poll / epoll / kqueue / iocp)

六、"多路复用 + 多线程":现代高性能服务器骨架

6.1 Reactor + Worker Pool

关键点:

  • 「1 个 Reactor 线程」(也有 ≥ 1,绑定不同核):管理 epoll,「只做 I/O + 事件调度」
  • 「N 个 Worker 线程」:负责「业务逻辑」(CPU 密集或短阻塞)
  • 通信:「Task Queue(prod-cons)」 + eventfd 跨线程唤醒 epoll
Reactor thread:┌─────────────────┐│ epoll_wait ...  ││  new_conn   -> accept & epoll_add│  read req   -> task_enqueue(worker_pool)│  writable   -> flush response└─────────────────┘           |           v  task queue┌──────────────────────────────────────────────┐│             worker threads                    ││  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐        ││  │  T0  │ │  T1  │ │  T2  │ │  T3  │ ...    ││  └──────┘ └──────┘ └──────┘ └──────┘        │└──────────────────────────────────────────────┘

这样一种服务器「同时拥有」

  • I/O 密集部分 = 多连接 epoll(线性扩展到 1w+ 连接)
  • CPU 密集部分 = 多 Worker(线性利用多核)
  • 临界区只有"task 入队 / 出队"

6.2 多 Reactor(SubReactor)

多线程同时 epoll(通常配合 SO_REUSEPORT 让内核把连接亲和绑定到某线程):

  • I/O 线程按比例接收连接
  • 每个 Reactor 固定负责自己的一组连接(线程封闭)
  • 跨 Reactor 的消息走 「lock-free ring」(DPDK rte_ring、LMAX Disruptor 风格的 ring buffer)

典型用途:高吞吐网关、金融交易、CDN 边缘缓存。

6.3 Thread-per-core + DPDK(了解)

某些极致场景(10G+ / 100G 网卡、低延迟交易):彻底不用内核协议栈 + epoll,自己绑核、用户态 TCP/IP(DPDK、mTCP、F-Stack)。思路核心:

  • 「每核独占一组资源」(run-to-completion,cache 友好)
  • 零锁、零上下文切换
  • 用 polling 替代 interrupt 驱动(CPU burn 换延迟)

代价:开发复杂度、兼容性、可调试性都大幅升高,适合"吞吐指标远超一般业务"的细分领域。

七、线程 + 多路复用联合下的易错点

错误
后果
正确做法
Reactor 线程做 CPU 密集运算
整个 loop 卡死,事件饿死
把计算丢到 worker pool
线程 A 的 fd 被线程 B 直接 epoll_ctl
race,EPOLL_CTL_MOD 在历史上非原子
把 DEL/ADD 操作收拢到 Reactor 线程统一执行
多线程同时 epoll_wait 监听同一组 fd
「thundering herd」
 多个线程被同一事件唤醒又多数空跑
EPOLLEXCLUSIVE
(Linux 4.5+)或单 Reactor 模式
ET 模式 + blocking I/O
永远阻塞在 read,等不到后续事件
强制 non-blocking,并读到 EAGAIN / 写到 EAGAIN
多线程写同一 socket
数据交叉、长度错误
唯一写 owner,或加锁保护写操作,或 IO 线程统一写

八、调试 / 性能工具小抄

工具
用途
perf top
 / perf record
找热点函数、LBR 回溯
strace -c -p <pid>
看系统调用分布和耗时
valgrind --tool=helgrind
数据竞争 + 死锁检测
valgrind --tool=drd
竞争 + 度量
ThreadSanitizer (TSan)
更高的性能竞争检测(-fsanitize=thread
bpftrace
 / bcc + offcputime
观察线程锁等待时长
htop
 / pidstat -t
看 CPU 热门的线程

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-21 18:19:46 HTTP/2.0 GET : https://f.mffb.com.cn/a/504029.html
  2. 运行时间 : 0.250917s [ 吞吐率:3.99req/s ] 内存消耗:4,942.47kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=d0d16149ec6a2ee4ee8a8e651c1cf0f3
  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.001037s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001425s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.001126s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000686s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001388s ]
  6. SELECT * FROM `set` [ RunTime:0.000616s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001487s ]
  8. SELECT * FROM `article` WHERE `id` = 504029 LIMIT 1 [ RunTime:0.001384s ]
  9. UPDATE `article` SET `lasttime` = 1787307586 WHERE `id` = 504029 [ RunTime:0.066260s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000664s ]
  11. SELECT * FROM `article` WHERE `id` < 504029 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001626s ]
  12. SELECT * FROM `article` WHERE `id` > 504029 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001112s ]
  13. SELECT * FROM `article` WHERE `id` < 504029 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.002861s ]
  14. SELECT * FROM `article` WHERE `id` < 504029 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002061s ]
  15. SELECT * FROM `article` WHERE `id` < 504029 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.003627s ]
0.255244s