结合Golang语言说明对多线程编程以及 select/epoll等网络模型的使用
首先介绍select和epoll这两个I/O多路复用的网络模型然后介绍多线程编程最后结合Go语言项目举例说明如何应用一、select 和 epoll 的介绍1. select 模型select 是一种I/O多路复用技术它允许程序同时监视多个文件描述符通常是套接字等待一个或多个描述符就绪可读、可写或异常然后进行相应的操作,它的跨平台兼容性好Windows/Linux/macOS核心原理​​使用fd_set数据结构管理文件描述符集合通过select()系统调用阻塞监听多个文件描述符每次调用都需要重新传递所有描述符集合select的缺点:支持的文件描述符数量有限通常1024,FD_SETSIZE限制每次调用都需要将文件描述符集合从用户态拷贝到内核态开销大内核遍历所有文件描述符(O(n)复杂度)来检查就绪状态效率不高需要手动维护描述符集合//c语言 fd_set read_fds; int max_fd 0; // 添加 socket 到监控集 FD_ZERO(read_fds); FD_SET(sockfd, read_fds); max_fd (sockfd max_fd) ? sockfd : max_fd; while(1) { fd_set tmp_fds read_fds; int ret select(max_fd 1, tmp_fds, NULL, NULL, NULL); for (int i 0; i max_fd; i) { if (FD_ISSET(i, tmp_fds)) { if (i sockfd) { // 处理新连接 } else { // 处理客户端数据 } } } }2. epoll 模型epoll 是Linux下高性能的I/O多路复用机制解决了select的缺点​​核心原理​​使用epoll_create创建 epoll 实例通过epoll_ctl动态添加/删除文件描述符通过epoll_wait获取就绪事件特点支持的文件描述符数量不受限制,海量并发连接(仅受系统最大打开文件数限制(系统内存限制))使用事件驱动避免遍历所有文件描述符(O(1)事件复杂度)通过内存映射技术避免用户态和内核态之间频繁拷贝Linux 专有高性能模型支持边缘触发ET和水平触发LT模式epoll有两种工作模式LTLevel Trigger水平触发只要文件描述符就绪就会触发通知默认ETEdge Trigger边缘触发只有状态变化时触发通知效率更高但要求用户必须一次性处理完所有数据//c语言 int epfd epoll_create1(0); struct epoll_event ev, events[MAX_EVENTS]; // 添加 socket ev.events EPOLLIN; ev.data.fd sockfd; epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, ev); while(1) { int nfds epoll_wait(epfd, events, MAX_EVENTS, -1); for (int i 0; i nfds; i) { if (events[i].data.fd sockfd) { // 接收新连接 int client accept(sockfd, ...); ev.data.fd client; epoll_ctl(epfd, EPOLL_CTL_ADD, client, ev); } else { // 处理客户端数据 recv(events[i].data.fd, ...); } } }二、多线程编程多线程允许程序同时运行多个任务,线程共享进程的地址空间和资源但每个线程有自己的栈和寄存器。多线程编程需要注意线程同步使用互斥锁(mutex)、条件变量condition variable、信号量等防止竞态条件死锁避免多个线程互相等待对方释放锁线程安全确保多个线程同时执行同一段代码时不会产生问题典型应用场景​​CPU 密集型任务如视频编码阻塞操作处理如文件 I/O多核并行计算// ​​C 线程池示例​​ class ThreadPool { public: ThreadPool(size_t threads) { for(size_t i0; ithreads; i) workers.emplace_back([this]{ while(true) { std::functionvoid() task; { std::unique_lockstd::mutex lock(queue_mutex); condition.wait(lock, [this]{ return stop || !tasks.empty(); }); if(stop tasks.empty()) return; task std::move(tasks.front()); tasks.pop(); } task(); } }); } templateclass F void enqueue(F f) { { std::unique_lockstd::mutex lock(queue_mutex); tasks.emplace(std::forwardF(f)); } condition.notify_one(); } ~ThreadPool() { { std::unique_lockstd::mutex lock(queue_mutex); stop true; } condition.notify_all(); for(std::thread worker: workers) worker.join(); } private: std::vectorstd::thread workers; std::queuestd::functionvoid() tasks; std::mutex queue_mutex; std::condition_variable condition; bool stop false; }; // 使用示例 ThreadPool pool(4); pool.enqueue([]{ processTask(); });三、Go语言中的应用Go语言通过goroutine和channel提供并发支持。goroutine是轻量级线程由Go运行时管理开销小。同时Go提供了select语句用于处理多个channel的通信,Go语言的网络模型基于非阻塞I/O和I/O多路复用底层使用epoll/kqueue等通过goroutine和channel实现高并发Go 语言并发模型特点​:​​​Goroutine​​轻量级线程协程初始栈仅 2KB​​Channel​​类型安全的通信管道解决数据竞争问题​​select 语句​​监听多个 channel 操作​​Epoll 集成​​net 包底层自动使用 epoll/kqueue​​GMP 调度器​​高效管理百万级 goroutine示例1使用select处理多个channelpackage main import ( fmt time ) func main() { ch1 : make(chan string) ch2 : make(chan string) go func() { time.Sleep(1 * time.Second) ch1 - one }() go func() { time.Sleep(2 * time.Second) ch2 - two }() for i : 0; i 2; i { select { case msg1 : -ch1: fmt.Println(received, msg1) case msg2 : -ch2: fmt.Println(received, msg2) } } }示例2使用goroutine和net包实现高并发TCP服务器package main import ( bufio fmt net strings ) func handleConnection(conn net.Conn) { defer conn.Close() fmt.Println(Accepted connection from, conn.RemoteAddr()) reader : bufio.NewReader(conn) for { message, err : reader.ReadString(\n) if err ! nil { fmt.Println(Connection closed by client) return } fmt.Print(Message received:, string(message)) response : strings.ToUpper(message) conn.Write([]byte(response)) } } func main() { listener, err : net.Listen(tcp, :8080) if err ! nil { fmt.Println(Error listening:, err) return } defer listener.Close() fmt.Println(Server listening on :8080) for { conn, err : listener.Accept() if err ! nil { fmt.Println(Error accepting connection:, err) continue } go handleConnection(conn) // 每个连接一个goroutine } }示例3使用epollGo的net包已经封装但可以通过syscall包直接使用epoll仅作演示在Go中通常不直接使用epoll而是利用net包和goroutine的并发模型,但下面是一个直接使用epoll的简单示例package main import ( fmt golang.org/x/sys/unix net os ) const maxEvents 10 func main() { // 创建socket fd, err : unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) if err ! nil { fmt.Println(Error creating socket:, err) os.Exit(1) } defer unix.Close(fd) // 设置地址重用 err unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) if err ! nil { fmt.Println(Error setting SO_REUSEADDR:, err) os.Exit(1) } // 绑定地址 addr : unix.SockaddrInet4{ Port: 8080, Addr: [4]byte{0, 0, 0, 0}, } err unix.Bind(fd, addr) if err ! nil { fmt.Println(Error binding:, err) os.Exit(1) } // 监听 err unix.Listen(fd, maxEvents) if err ! nil { fmt.Println(Error listening:, err) os.Exit(1) } // 创建epoll实例 epollFd, err : unix.EpollCreate1(0) if err ! nil { fmt.Println(Error creating epoll instance:, err) os.Exit(1) } defer unix.Close(epollFd) event : unix.EpollEvent{ Events: unix.EPOLLIN, Fd: int32(fd), } err unix.EpollCtl(epollFd, unix.EPOLL_CTL_ADD, fd, event) if err ! nil { fmt.Println(Error adding fd to epoll:, err) os.Exit(1) } var events [maxEvents]unix.EpollEvent for { n, err : unix.EpollWait(epollFd, events[:], -1) if err ! nil { fmt.Println(Error in EpollWait:, err) continue } for i : 0; i n; i { if int(events[i].Fd) fd { // 有新的连接 connFd, _, err : unix.Accept(fd) if err ! nil { fmt.Println(Error accepting connection:, err) continue } connEvent : unix.EpollEvent{ Events: unix.EPOLLIN | unix.EPOLLET, // ET模式 Fd: int32(connFd), } err unix.EpollCtl(epollFd, unix.EPOLL_CTL_ADD, connFd, connEvent) if err ! nil { fmt.Println(Error adding connFd to epoll:, err) unix.Close(connFd) continue } fmt.Println(Accepted new connection) } else { // 连接有数据可读 connFd : int(events[i].Fd) buf : make([]byte, 1024) n, err : unix.Read(connFd, buf) if err ! nil || n 0 { // 连接断开 unix.Close(connFd) fmt.Println(Connection closed) continue } fmt.Printf(Read %d bytes from connFd %d: %s\n, n, connFd, string(buf[:n])) // 回写 unix.Write(connFd, buf[:n]) } } } }示例4: WebSocket 服务器​package main import ( net/http github.com/gorilla/websocket sync ) var upgrader websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }} var connections sync.Map func wsHandler(w http.ResponseWriter, r *http.Request) { conn, _ : upgrader.Upgrade(w, r, nil) defer conn.Close() // 注册连接 connections.Store(conn, true) defer connections.Delete(conn) for { // 消息处理非阻塞读取 _, msg, err : conn.ReadMessage() if err ! nil { break } // 广播消息并发安全 connections.Range(func(k, v interface{}) bool { if client, ok : k.(*websocket.Conn); ok { go func() { // 每个发送使用独立goroutine client.WriteMessage(websocket.TextMessage, msg) }() } return true }) } } func main() { // 配置epoll网络模型自动生效 http.HandleFunc(/ws, wsHandler) // 启动4个工作线程处理网络I/O for i : 0; i 4; i { go func() { http.ListenAndServe(:8080, nil) }() } select {} // 永久阻塞 }注意在Go中通常使用net包而不是直接调用系统调用因为net包已经高效地封装了I/O多路复用并且配合goroutine更易于管理四.核心优化技术说明​​1.​​Epoll 自动化​​Go 的 net 包自动使用最佳系统调用Linux 使用 epollmacOS 使用 kqueue通过netpoll实现高效 I/O 多路复用​​2.Goroutine 管理​​每个连接独立 goroutine 处理使用sync.Map实现并发安全的连接池Range方法避免全局锁竞争​​3.Channel 工作池​​func worker(jobs -chan Message) { for msg : range jobs { process(msg) // 业务处理 } } func main() { // 创建带缓冲的Channel jobQueue : make(chan Message, 1000) // 启动工作池 for i : 0; i runtime.NumCPU(); i { go worker(jobQueue) } // 接收消息时投递 go func() { for msg : range messageChannel { select { case jobQueue - msg: // 正常投递 default: // 队列满时丢弃消息 log.Println(Job queue full!) } } }() }4.​​性能优化要点​​// 1. 调整调度器参数 runtime.GOMAXPROCS(12) // 设置使用的CPU核心数 // 2. 对象复用池减少GC压力 var bufPool sync.Pool{ New: func() interface{} { return make([]byte, 1024) }, } // 3. 流量控制 rateLimiter : make(chan struct{}, 1000) // 限制并发处理数 // 4. 开启TCP快速打开 ln, _ : net.ListenConfig{ FastOpen: true, KeepAlive: 30 * time.Second, }.Listen(tcp, :80)五.总结性能对比表模型并发处理能力CPU占用内存开销编程复杂度多线程select1K~10K高高中等epoll线程池100K中中等高GoGoroutine1M低极低低select和epoll都是I/O多路复用机制epoll效率更高多线程编程需要注意同步、死锁和线程安全Go语言通过goroutine和channel实现高并发网络模型底层使用epoll等但通过net包封装简化了编程在Go项目中通常使用goroutine处理并发连接每个连接一个goroutine示例2或者使用worker池来避免大量goroutine的创建如果连接数非常多。同时可以利用select语句处理多个channel的通信示例1。直接使用epoll的情况较少示例3主要用于理解底层机制因为标准库已经提供了很好的抽象最佳实践建议​​Linux 环境直接采用 Go 的 net 包实现高并发CPU 密集型任务配合runtime.GOMAXPROCS()调优使用 pprof 监控 goroutine 泄漏问题敏感数据操作采用sync/atomic避免锁竞争利用io.Reader和bytes.Buffer实现零拷贝处理

相关新闻

winit 0.18 版本解析:跨平台窗口库的键位扩展、Wayland 装饰与各平台稳定性修复

winit 0.18 版本解析:跨平台窗口库的键位扩展、Wayland 装饰与各平台稳定性修复

桌面应用跨平台 【免费下载链接】winit Window handling library in pure Rust 项目地址: https://gitcode.com/GitHub_Trending/wi/winit 点击查看 免费下载 winit 是一个用纯 Rust 编写的跨平台窗口处理库,其 0.18 系列(0.18.0 与 0.18.1&…

2026/10/3 9:43:45 阅读更多 →
AISystem 模型轻量化之 FBNet 系列:从 DNAS 搜索到 JointNAS 联合优化

AISystem 模型轻量化之 FBNet 系列:从 DNAS 搜索到 JointNAS 联合优化

文档教程人工智能 【免费下载链接】AISystem AISystem 主要是指AI系统,包括AI芯片、AI编译器、AI推理和训练框架等AI全栈底层技术 项目地址: https://gitcode.com/GitHub_Trending/ai/AISystem 点击查看 免费下载 FBNet 是 Facebook 提出的轻量级卷积神…

2026/10/3 9:43:45 阅读更多 →
AI辅助做PPT的正确姿势:从大纲到排版,30分钟产出可交付演示文稿

AI辅助做PPT的正确姿势:从大纲到排版,30分钟产出可交付演示文稿

1. 先搞懂AI做PPT的正确姿势:它不是替身,是杠杆网上聊AI做PPT,十个人里有八个人说的是"一键生成完整PPT"。输个主题,等十几秒,出来一套二三十页的成品,看着挺唬人,真拿去开会或者交作…

2026/10/2 7:55:32 阅读更多 →

最新新闻

TypeScript深入浅出:函数参数为何逆变?协变与逆变完全解析

TypeScript深入浅出:函数参数为何逆变?协变与逆变完全解析

最近有同事跑过来问我一个类型报错:他给一个事件处理器写了(e: MouseEvent) > void,正要赋给一个声明为(e: Event) > void的回调,结果 TypeScript 直接把他拦住了。我解释了两句,他冒出一句:所以函数参数到底是协…

2026/10/3 9:44:14 阅读更多 →
无人机芯片模块设计实战:飞控选型、接口调试与可靠性优化

无人机芯片模块设计实战:飞控选型、接口调试与可靠性优化

无人机这行干久了就会发现,真正把飞机调稳、把功能做扎实,拼的往往不是某一个酷炫的算法,而是藏在机身里那一颗颗芯片和围绕它们展开的模块设计。飞控选什么主控、通信走什么接口、电源怎么监测、视觉算力够不够,这些看似枯燥的技…

2026/10/3 9:44:13 阅读更多 →
Coze低代码Agent开发框架实操指南:五个核心模块与工程落地

Coze低代码Agent开发框架实操指南:五个核心模块与工程落地

这篇是系列第二篇,接着上一篇聊。上篇我讲了为什么低代码Agent开发框架会在2025年之后成为企业落地AI的主流选择,以及Agent开发与传统软件开发的本质区别。这一篇直接落到实操工具上,把Coze平台的核心功能彻底拆开揉碎,给出一份“…

2026/10/3 9:44:13 阅读更多 →
七自由度车辆动力学模型:从方程到仿真实战解析

七自由度车辆动力学模型:从方程到仿真实战解析

方向盘刚转到30度,轮胎和地面摩擦发出的尖啸声就穿透了车窗。这熟悉的失控感让我突然想到——搞车辆仿真的那会儿,被七自由度模型折腾的日日夜夜,可不比现在轻松多少。很多人以为车辆仿真就是把坐标和速度扔给计算机,跑一个动画就…

2026/10/3 9:44:13 阅读更多 →
Java为什么能跨平台?JVM、字节码与一次编译到处运行的底层原理

Java为什么能跨平台?JVM、字节码与一次编译到处运行的底层原理

经常有初学者问我:Java为什么可以跨平台?在准备面试的人嘴里,这更是一道高频题。我先给一个最短的答案——因为有JVM。但如果你只答这一句,面试基本就凉了,因为紧接着就会追问:JVM是怎么实现跨平台的&#…

2026/10/3 9:44:11 阅读更多 →
数据库行式存储详解:原理、优势、调优与场景选型

数据库行式存储详解:原理、优势、调优与场景选型

1. 行式存储是什么:先搞清楚“一行数据”到底存在哪 1.1 从表到页到行:存储引擎的最小组织单元 很多人一听到“行式存储”,第一反应就是“这不就是普通的数据库表吗”。这个理解没有错,但不完整。行式存储的准确含义是&#xff1…

2026/10/3 9:43:10 阅读更多 →

日新闻

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南 【免费下载链接】ex-skill 前任 skill 项目地址: https://gitcode.com/gh_mirrors/exsk/ex-skill 前任.skill 是一个运行在 Claude Code 上的开源 Skill:导入微信、iMessage、短信、…

2026/10/3 0:00:27 阅读更多 →
45个经典Linux面试题:从命令到网络排障的完整考点解析

45个经典Linux面试题:从命令到网络排障的完整考点解析

刚开始带应届生的时候,我最头疼的就是他们拿着一摞Linux面试题背得滚瓜烂熟,一上机全露馅。后来自己从被面的人变成面别人的人,才慢慢摸清楚:Linux面试题考的根本不是答案本身,而是你面对一个不确定的系统问题时&#…

2026/10/3 0:01:28 阅读更多 →
SAP生产预留实战指南:MB21/MB23/MB25协同与MRP集成

SAP生产预留实战指南:MB21/MB23/MB25协同与MRP集成

简介:本资源是一份面向SAP ABAP开发人员、生产计划专员及ERP实施顾问的实操型操作指南,聚焦SAP生产预留核心业务场景,系统解决物料预留创建、查询、校验与批量处理等高频问题。文档以结构化方式覆盖预留背景原理、OMC2编码规则、工厂级参数配…

2026/10/3 0:01:28 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/3 9:14:33 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/1 19:41:40 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/10/3 9:42:31 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:35 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:36 阅读更多 →