Go 入门到精通-19-Goroutine 入门
目录 Go 入门到精通Goroutine 入门 —— 轻量级并发的秘密1. 开篇Go 并发的灵魂2. goroutine 是什么2.1 一句话定义2.2 核心特征3. go 关键字一行代码启动并发3.1 基本语法3.2 闭包陷阱4. 主 goroutine 退出即结束5. sync.WaitGroup等待协程完成5.1 基本用法5.2 WaitGroup 使用原则5.3 WaitGroup 最佳实践模式6. goroutine vs 线程全方位对比6.1 对比表6.2 规模演示7. GMP 调度模型深度解析7.1 GMP 三元素7.2 GMP 调度流程7.3 工作窃取Work Stealing图示7.4 Goroutine 生命周期8. GOMAXPROCS并发度的控制旋钮8.1 基本概念8.2 GOMAXPROCS 的影响8.3 并发 vs 并行9. runtime 包窥探运行时9.1 runtime 常用函数速查10. goroutine 不是银弹陷阱与反思10.1 过度创建 goroutine10.2 goroutine 泄漏10.3 Goroutine 使用清单11. 实战并发爬虫框架12. 小结与互动核心要点回顾 GMP 结构记忆 思考题 互动 Go 入门到精通Goroutine 入门 —— 轻量级并发的秘密 更新于 2026年7月 | ✍️ 原创文章转载请注明出处1. 开篇Go 并发的灵魂如果说 Go 语言有什么杀手级特性那goroutine必然排在第一位。在 Go 中启动一个并发任务只需要一个go关键字godoSomething()// 搞定而在传统线程模型中这意味着几十 KB 的栈空间分配、内核线程创建、复杂的线程池管理……这篇文章将带你从零开始理解 goroutine——从它的轻量本质到 GMP 调度模型从基本用法到高级陷阱为后面的 channel 学习打下坚实基础。2. goroutine 是什么2.1 一句话定义goroutine 是 Go 运行时管理的轻量级用户态线程协程初始栈大小仅 2KB由 Go 调度器GMP模型在操作系统线程上复用调度。2.2 核心特征// goroutine 的四个核心特征// 1️⃣ 轻量初始栈仅 2KB线程通常是 1-8MB// 2️⃣ 动态栈栈空间按需伸缩最大可达 1GB// 3️⃣ 用户态调度不由 OS 内核调度切换成本极低~200ns vs 线程 ~1-10µs// 4️⃣ 与 Go 运行时深度集成GC、channel、select 等原生支持特性goroutineOS 线程初始栈大小~2KB~1-8 MB栈增长方式动态伸缩固定大小创建开销数微秒数百微秒 ~ 毫秒切换开销~200 ns~1-10 µs调度方式Go 运行时用户态OS 内核数量上限数十万 ~ 百万数千标识无内置 ID有 TID3. go 关键字一行代码启动并发3.1 基本语法packagemainimport(fmttime)funcsayHello(){fmt.Println(Hello from goroutine!)}funcmain(){// 启动一个 goroutinegosayHello()// 匿名函数 goroutinegofunc(){fmt.Println(Hello from anonymous goroutine!)}()// 带参数的 goroutinegofunc(namestring){fmt.Printf(Hello, %s!\n,name)}(Go 2026)// ⚠️ 必须等待否则 main 退出goroutine 来不及执行time.Sleep(100*time.Millisecond)}3.2 闭包陷阱funcmain(){// ❌ 经典错误闭包捕获了循环变量fori:0;i5;i{gofunc(){fmt.Println(i)// 可能全打印 5}()}time.Sleep(time.Second)// 输出5 5 5 5 5大概率fmt.Println(---)// ✅ 正确方式1传参复制fori:0;i5;i{gofunc(nint){fmt.Println(n)}(i)}time.Sleep(time.Second)// ✅ 正确方式2局部变量复制Go 1.22 循环变量语义已改进fori:0;i5;i{i:i// 显式复制gofunc(){fmt.Println(i)}()}time.Sleep(time.Second)}4. 主 goroutine 退出即结束这是初学者最容易犯的错误之一funcmain(){// ❌ 可能什么都看不到gofunc(){fmt.Println(这条消息可能永远不会被打印)}()// main 函数返回 → 进程退出 → 所有 goroutine 被强制终止}Go 程序的规则main函数本身运行在 main goroutine 中main goroutine 退出 → 整个程序立即退出不会等待其他 goroutine 完成// 图解// main goroutine ──────────────────────▶ 退出 // │// go func() ───────┼── 正在执行... ──▶ 被强制终止 ☠️// │// time ────────────▶5. sync.WaitGroup等待协程完成sync.WaitGroup是等待一组 goroutine 完成的标准工具可以看作一个线程安全的计数器。5.1 基本用法packagemainimport(fmtsynctime)funcworker(idint,wg*sync.WaitGroup){deferwg.Done()// ⭐ 确保计数器减一即使 panicfmt.Printf(Worker %d 开始\n,id)time.Sleep(time.Duration(id)*100*time.Millisecond)fmt.Printf(Worker %d 完成\n,id)}funcmain(){varwg sync.WaitGroupfori:1;i5;i{wg.Add(1)// 计数器 1goworker(i,wg)}wg.Wait()// 阻塞直到计数器归零fmt.Println(所有 Worker 完成)}5.2 WaitGroup 使用原则// ✅ 三条铁律// 1. Add 必须在 goroutine 启动前调用// 2. Done 必须在 goroutine 内部调用通常用 defer// 3. WaitGroup 必须通过指针传递不能值拷贝// ❌ 错误示例1Add 在 goroutine 内部varwg sync.WaitGroupfori:0;i5;i{gofunc(){wg.Add(1)// ❌ 可能在 Wait 之后调用deferwg.Done()// ...}()}wg.Wait()// ❌ 错误示例2值传递funcwrongWorker(wg sync.WaitGroup){// ❌ 值拷贝deferwg.Done()}// 应该传指针func worker(wg *sync.WaitGroup)5.3 WaitGroup 最佳实践模式// 模式1循环启动funclaunchWorkers(nint){varwg sync.WaitGroup wg.Add(n)// 一次性设置总数fori:0;in;i{gofunc(idint){deferwg.Done()doWork(id)}(i)}wg.Wait()}// 模式2逐个添加funclaunchDynamic(){varwg sync.WaitGroupfor_,task:rangetasks{wg.Add(1)// 逐个添加gofunc(t Task){deferwg.Done()process(t)}(task)}wg.Wait()}// 模式3封装为工具函数funcConcurrentExec(tasks[]func()){varwg sync.WaitGroup wg.Add(len(tasks))for_,task:rangetasks{task:task// 复制gofunc(){deferwg.Done()task()}()}wg.Wait()}6. goroutine vs 线程全方位对比6.1 对比表维度goroutineOS 线程 (Java Thread)内存开销初始 2KB动态伸缩固定 1-8MB创建速度~2-3 µs~50-100 µs切换开销~200 ns用户态~1-10 µs内核态调度器Go GMP 调度器OS 内核调度器上下文切换用户态切换无需陷入内核内核态切换保存/恢复大量寄存器数量规模轻松百万级通常几千受内存限制抢占方式协作式 信号抢占Go 1.14时间片抢占标识无 goroutine ID故意隐藏有 Thread ID局部存储无推荐 context 传递ThreadLocal6.2 规模演示funcmain(){// 启动 10 万个 goroutine内存仅增加约 200MBvarwg sync.WaitGroup wg.Add(100_000)fori:0;i100_000;i{gofunc(idint){deferwg.Done()time.Sleep(time.Second)}(i)}fmt.Println(10万个 goroutine 已启动)wg.Wait()fmt.Println(全部完成)}如果用 OS 线程实现同样的功能100,000 × 1MB ~100GB 内存基本不可行。7. GMP 调度模型深度解析7.1 GMP 三元素Go 的并发调度模型称为GMP 模型┌──────────────────────────────────────────┐ │ GMP 调度模型 │ │ │ │ G ── G ── G ── G ── G (Goroutine) │ │ │ │ │ │ P ─────── P ─────── P (Processor) │ │ │ │ │ │ │ M ─────── M ─────── M (Machine) │ │ │ │ │ │ │ [CPU] [CPU] [CPU] │ └──────────────────────────────────────────┘元素全称含义数量GGoroutine用户态协程承载任务成千上万MMachineOS 线程真正执行代码动态变化PProcessor逻辑处理器持有本地运行队列GOMAXPROCS默认 CPU 核数7.2 GMP 调度流程// GMP 工作流程简化版// 1. 每个 P 维护一个本地 goroutine 队列runq// 2. P 与 M 绑定M 从 P 的本地队列取 G 执行// 3. 当 M 因系统调用阻塞时P 会与 M 解绑寻找新的 M// 4. 当 M 的 G 阻塞在 channel/网络 I/O 时G 被挂起M 继续执行其他 G// 5. 当 P 的本地队列为空时从全局队列或偷其他 P 的 G// 核心设计原则// - M 是计算资源P 是调度资源G 是任务// - M:P 通常 1:1但 P 可以在 M 之间迁移// - 工作窃取Work Stealing空闲 P 从忙碌 P 偷 G7.3 工作窃取Work Stealing图示P1 (忙碌) P2 (空闲) ┌─────────┐ ┌─────────┐ │ G1 G2 G3│ │ (空) │ │ G4 G5 G6│ │ │ │ G7 G8 G9│ ── steal──▶│ G7 G8 G9 │ └─────────┘ └─────────┘当 P2 的本地队列为空时它会从 P1 偷一半的 goroutine。这种设计确保了负载均衡。7.4 Goroutine 生命周期┌──────┐ go func() ┌──────────┐ 执行完毕 ┌──────┐ │ 创建 │ ──────────▶ │ 可运行 │ ────────▶ │ 退出 │ └──────┘ └──────────┘ └──────┘ │ ┌────────┼────────┐ ▼ ▼ ▼ ┌─────────┐ ┌────────┐ ┌──────────┐ │channel │ │ 网络I/O│ │ 系统调用 │ │等待 │ │ 等待 │ │ 阻塞 │ └─────────┘ └────────┘ └──────────┘ │ │ │ └────────┼────────┘ ▼ ┌──────────┐ │ 可运行 │ (等待重新调度) └──────────┘8. GOMAXPROCS并发度的控制旋钮8.1 基本概念GOMAXPROCS决定了同时执行 Go 代码的 OS 线程数量上限即 P 的数量。packagemainimport(fmtruntime)funcmain(){// 查看当前值fmt.Println(GOMAXPROCS:,runtime.GOMAXPROCS(0))// 默认 CPU 核数// 设置新值返回旧值old:runtime.GOMAXPROCS(4)fmt.Println(旧值:,old)// 也可以通过环境变量设置// GOMAXPROCS4 go run main.go}8.2 GOMAXPROCS 的影响GOMAXPROCS 值效果1单核执行无真正的并行但 goroutine 仍可并发NN CPU核数限制并行度为其他应用留出 CPUCPU核数默认充分利用多核 CPU核数无额外收益增加调度开销8.3 并发 vs 并行并发单核GOMAXPROCS1 G1: ──▶──▶── G2: ──▶──▶── G3: ──▶──▶── 单个 CPU 交替执行 并行多核GOMAXPROCS4 CPU1: G1 ────────▶ CPU2: G2 ────────▶ CPU3: G3 ────────▶ CPU4: G4 ────────▶ 同时执行 Go 的哲学Don’t communicate by sharing memory; share memory by communicating.不通过共享内存来通信而通过通信来共享内存—— 这将在下一篇 Channel 详解中展开。9. runtime 包窥探运行时packagemainimport(fmtruntimetime)funcmain(){// NumGoroutine当前 goroutine 数量fmt.Println(goroutine 数量:,runtime.NumGoroutine())// 至少 1main// NumCPU逻辑 CPU 数量fmt.Println(CPU 核心数:,runtime.NumCPU())// GOMAXPROCS当前 P 的数量fmt.Println(GOMAXPROCS:,runtime.GOMAXPROCS(0))// Gosched主动让出 CPUgofunc(){fori:0;i5;i{fmt.Println(goroutine A:,i)runtime.Gosched()// 让出执行权}}()gofunc(){fori:0;i5;i{fmt.Println(goroutine B:,i)runtime.Gosched()}}()time.Sleep(time.Second)// Goexit终止当前 goroutine但不影响其他gofunc(){deferfmt.Println(defer 仍会执行)runtime.Goexit()// 终止 goroutinedefer 会执行fmt.Println(这行不会执行)}()time.Sleep(100*time.Millisecond)fmt.Println(main 结束goroutine 数量:,runtime.NumGoroutine())// LockOSThread绑定当前 goroutine 到 OS 线程// 适用于需要线程局部存储的 CGO 调用// runtime.LockOSThread()// defer runtime.UnlockOSThread()}9.1 runtime 常用函数速查函数用途runtime.NumGoroutine()当前 goroutine 数量调试用runtime.NumCPU()逻辑 CPU 核心数runtime.GOMAXPROCS(n)设置/查询 P 的数量runtime.Gosched()主动让出 CPU 时间片runtime.Goexit()终止当前 goroutineruntime.LockOSThread()绑定 goroutine 到 OS 线程runtime.GC()手动触发 GC慎用runtime.ReadMemStats()读取内存统计10. goroutine 不是银弹陷阱与反思10.1 过度创建 goroutine// ❌ 坏习惯每个请求创建一个无界数量的 goroutinefunchandleRequest(w http.ResponseWriter,r*http.Request){items:fetchAllItems()// 可能有 10 万条for_,item:rangeitems{goprocessItem(item)// 瞬间创建 10 万个 goroutine}}// ✅ 正确做法使用工作池worker pool或 semaphore 控制并发度funchandleRequestProperly(items[]Item){constmaxConcurrency100sem:make(chanstruct{},maxConcurrency)varwg sync.WaitGroupfor_,item:rangeitems{wg.Add(1)sem-struct{}{}// 获取令牌gofunc(it Item){deferwg.Done()deferfunc(){-sem}()// 释放令牌processItem(it)}(item)}wg.Wait()}10.2 goroutine 泄漏// ❌ goroutine 泄漏channel 永远没有接收者funcleak(){ch:make(chanint)gofunc(){ch-42// 永远阻塞goroutine 泄漏}()// 忘记从 ch 读取}// ❌ 另一个泄漏场景无限循环的 goroutinefuncleak2(){gofunc(){for{// 做点什么...但没有退出条件time.Sleep(time.Second)}}()// 这个 goroutine 永远不会退出}// ✅ 正确做法提供退出机制funcnoLeak(ctx context.Context){gofunc(){for{select{case-ctx.Done():return// 正确退出default:// 做点什么time.Sleep(time.Second)}}}()}10.3 Goroutine 使用清单✅ 应该使用 goroutine❌ 不应使用 goroutineI/O 密集型任务网络、文件、数据库CPU 密集型计算任务超过 CPU 核数无收益独立的并行任务互不依赖强依赖顺序的任务需要异步执行的操作简单的 11杀鸡不用牛刀高并发服务每个连接一个 goroutine无需并发的场景定时/周期性任务为了炫耀技术11. 实战并发爬虫框架packagemainimport(fmtsynctime)// Crawler 并发爬虫typeCrawlerstruct{maxWorkersint}funcNewCrawler(maxWorkersint)*Crawler{returnCrawler{maxWorkers:maxWorkers}}// Crawl 并发爬取 URL 列表func(c*Crawler)Crawl(urls[]string)map[string]string{results:make(map[string]string)varmu sync.Mutexvarwg sync.WaitGroup// semaphore 控制并发数sem:make(chanstruct{},c.maxWorkers)for_,url:rangeurls{wg.Add(1)sem-struct{}{}gofunc(ustring){deferwg.Done()deferfunc(){-sem}()content:fetchURL(u)// 模拟抓取mu.Lock()results[u]content mu.Unlock()}(url)}wg.Wait()returnresults}funcfetchURL(urlstring)string{time.Sleep(200*time.Millisecond)// 模拟网络延迟returnfmt.Sprintf(Content of %s,url)}funcmain(){urls:make([]string,20)fori:0;i20;i{urls[i]fmt.Sprintf(http://example.com/page/%d,i)}crawler:NewCrawler(5)// 最多 5 个并发start:time.Now()results:crawler.Crawl(urls)elapsed:time.Since(start)fmt.Printf(爬取了 %d 个 URL耗时: %v\n,len(results),elapsed)// 20 个 URL5 并发 → 大约 4 轮 × 200ms ~800ms}12. 小结与互动核心要点回顾知识点记忆要点goroutine 概念轻量级用户态协程2KB 初始栈GMP 调度go 关键字一行启动并发但需要 WaitGroup 等待WaitGroupAdd/Done/Wait必须传指针GMP 模型G协程 M线程 P逻辑处理器GOMAXPROCS控制 P 的数量默认 CPU 核数Gosched主动让出Goexit 终止当前 goroutinegoroutine 泄漏永远阻塞无退出 → 内存泄漏并发控制semaphore/worker pool 限制并发度 GMP 结构记忆G → 要做什么任务 M → 谁来做干活的人OS线程 P → 在哪做工作台有工具和队列 M 必须绑定 P 才能执行 G P 的数量 GOMAXPROCS 思考题如果GOMAXPROCS1程序还会并发吗这与并行有何区别如何检测和排查 goroutine 泄漏提示runtime.NumGoroutine() pprof什么是工作窃取Work Stealing为什么它比全局队列更高效 互动你在项目中最多同时运行过多少个 goroutine有没有遇到过 goroutine 泄漏的坑欢迎在评论区分享你的并发经验‍作者布朗克168系列[Go 入门到精通 2026]上一篇[文件操作] | 下一篇[Channel 详解]如果你觉得这篇文章对你有帮助别忘了点赞 、收藏 ⭐ 和关注

相关新闻

AM62L SoC硬件防火墙配置实战:从原理到寄存器级安全策略实现

AM62L SoC硬件防火墙配置实战:从原理到寄存器级安全策略实现

1. 硬件防火墙在SoC设计中的核心地位与AM62L的实现在嵌入式系统,尤其是像AM62L这样的复杂SoC设计中,硬件防火墙早已不是“锦上添花”的选项,而是构建健壮、安全系统的基石。我接触过不少项目,初期为了赶进度,对防火墙配…

2026/7/19 3:15:29阅读更多 →
为什么 WPS 越用越卡?一次清理全部缓存

为什么 WPS 越用越卡?一次清理全部缓存

很多人遇到过这种情况:WPS 刚装好时飞快,用着用着就越来越卡,即使卸载重装也没用。本文将详细从让wps越用越卡的罪魁祸首——wps缓存来分析,并给出详细的清理教程。一、WPS 为什么会卡卡顿的核心是wps云文档的本地缓存机制。如果你…

2026/7/19 3:15:29阅读更多 →
Tableau计算字段、LOD与表计算三大核心原理全解析

Tableau计算字段、LOD与表计算三大核心原理全解析

1. 项目概述:为什么Tableau里的计算不是“加减乘除”,而是通往专业认证的必经关卡在准备Tableau Desktop Specialist认证考试的前两周,我重新打开自己三年前做的销售看板——那个被业务部门夸“一目了然”的仪表板,突然发现它根本…

2026/7/19 3:15:29阅读更多 →
STM32H7 SPI Flash下载算法开发指南

STM32H7 SPI Flash下载算法开发指南

1. 项目概述在嵌入式开发中,STM32H7系列微控制器因其高性能和丰富的外设接口而广受欢迎。其中SPI总线作为连接外部存储设备的重要通道,SPI Flash的编程一直是开发过程中的关键环节。传统方式需要先将程序下载到内部Flash,再通过应用程序烧写到…

2026/7/19 6:15:46阅读更多 →
2026年加固笔记本技术趋势与选购指南

2026年加固笔记本技术趋势与选购指南

1. 2026年笔记本电脑加固技术演进趋势在移动办公和户外作业需求激增的背景下,2026年的加固型笔记本市场呈现出三个显著的技术转向:首先是军用标准认证从传统的MIL-STD-810H向新一代810J迭代,新增了电磁脉冲(EMP)防护和…

2026/7/19 6:15:46阅读更多 →
JSON vs JSONL:从数据格式到 AI Agent 的工程实践

JSON vs JSONL:从数据格式到 AI Agent 的工程实践

文章目录一、JSON:我们熟悉的"完整对象"二、JSONL:行级独立的流式格式JSON vs JSONL 核心对比为什么 JSONL 特别适合"流"?三、Agent 场景中的 JSONL 实战3.1 Streaming API:一个请求,多条返回3.2 …

2026/7/19 6:15:46阅读更多 →
AI无法解析的域名:利用IDN与Punycode制造语义断层

AI无法解析的域名:利用IDN与Punycode制造语义断层

1. 项目概述:为什么一个域名能成为AI的“认知盲区” “The Only Domain AI Can’t Crack”——这个标题第一次出现在我邮箱订阅的某份技术简报里时,我下意识点开,以为又是一篇营销味浓重的AI焦虑文。结果通读下来,发现它根本不是…

2026/7/19 6:15:46阅读更多 →
缺失数据机制诊断:MCAR、MAR与MNAR的实战识别与处理

缺失数据机制诊断:MCAR、MAR与MNAR的实战识别与处理

1. 为什么缺失数据从来不是“随机消失”的——一个被严重低估的统计陷阱你手头有一份刚拿到的医疗研究数据集,1000名抑郁症患者参与了新药临床试验,三个月后,700人按时回访并提交了评估量表,剩下300人的数据栏里空空如也。项目组开…

2026/7/19 6:15:46阅读更多 →
嵌入式低功耗设计:深入解析PRCM电源时钟复位管理模块

嵌入式低功耗设计:深入解析PRCM电源时钟复位管理模块

1. 项目概述与PRCM核心价值在嵌入式系统,尤其是移动设备和物联网终端的开发中,我们常常面临一个核心矛盾:如何在提供强大计算性能的同时,实现极致的功耗控制,以延长电池续航。这个矛盾在早期的单片机时代并不突出&…

2026/7/19 6:13:45阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/19 0:01:04阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/19 0:01:04阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/19 0:01:04阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/19 0:01:04阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/19 0:01:04阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/19 0:01:04阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/18 22:49:46阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/18 14:49:24阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/18 18:49:35阅读更多 →