[{"data":1,"prerenderedAt":13198},["ShallowReactive",2],{"search-docs":3,"doc-\u002Finterview\u002Fgolang":886},[4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,159,162,165,169,172,175,178,182,186,190,194,198,202,206,210,214,218,222,226,230,234,238,242,246,250,254,258,262,266,269,273,277,281,285,288,291,294,298,301,304,307,310,313,316,319,322,325,329,332,336,340,344,348,352,356,359,362,365,368,371,374,377,380,383,386,389,393,396,399,402,405,408,411,414,417,420,424,428,432,435,438,442,446,450,454,458,462,466,470,474,477,480,483,487,491,494,497,500,504,507,511,515,518,521,524,527,530,533,536,539,542,545,548,551,554,557,560,563,566,569,572,575,579,583,587,591,595,599,603,606,610,614,617,620,623,626,629,633,637,640,643,646,649,652,655,658,661,664,667,670,673,676,679,682,685,688,691,694,697,700,703,706,709,712,716,720,724,728,732,736,740,744,748,752,756,760,764,768,772,775,779,783,787,790,793,796,799,802,805,808,811,814,818,822,825,829,832,835,838,841,844,848,851,854,858,862,865,869,873,876,879,882],{"path":5,"title":6,"description":7},"\u002Fabout\u002Fauthor","作者相关","只想纯粹的做一个程序员...",{"path":9,"title":10,"description":11},"\u002Fabout\u002Fjourney","心路历程","",{"path":13,"title":14,"description":15},"\u002Fai\u002Fagent\u002Fframeworks","Agent 框架","主流 Agent 框架：LangChain、LlamaIndex、AutoGen、CrewAI",{"path":17,"title":18,"description":19},"\u002Fai\u002Fagent\u002Fhooks","Agent Hooks 与自动化","Claude Agent 的 Hooks 生命周期、事件类型、典型自动化场景",{"path":21,"title":22,"description":23},"\u002Fai\u002Fagent\u002Fintroduction","AI Agent 概述","AI Agent 核心概念：感知、规划、执行、记忆",{"path":25,"title":26,"description":27},"\u002Fai\u002Fagent\u002Fpractice","Agent 实战","AI Agent 实战：构建自主任务执行系统",{"path":29,"title":30,"description":31},"\u002Fai\u002Fagent\u002Fsdk","Claude Agent SDK 开发","使用 Claude Agent SDK 构建自定义 AI Agent：架构、API、生命周期",{"path":33,"title":34,"description":35},"\u002Fai\u002Fagent\u002Fsubagents","Subagents 子代理","用 Subagents 分解复杂任务、并发执行、隔离上下文",{"path":37,"title":38,"description":39},"\u002Fai\u002Fagent\u002Ftool-use","工具调用","AI Agent 工具调用：Function Calling、Tool Use 原理与实践",{"path":41,"title":42,"description":43},"\u002Fai\u002Ffundamentals\u002Fdeep-learning","深度学习入门","深度学习基础知识：前向传播、反向传播、损失函数、优化器",{"path":45,"title":46,"description":47},"\u002Fai\u002Ffundamentals\u002Fml-basics","机器学习基础","机器学习核心概念：监督学习、无监督学习、强化学习",{"path":49,"title":50,"description":51},"\u002Fai\u002Ffundamentals\u002Fneural-networks","神经网络原理","神经网络架构：CNN、RNN、注意力机制",{"path":53,"title":54,"description":55},"\u002Fai\u002Fgetting-started","AI 学习路线","AI 技术学习路线图，从基础到实战的完整指南",{"path":57,"title":58,"description":59},"\u002Fai\u002Fllm\u002Ffine-tuning","模型微调","大模型微调技术：LoRA、QLoRA、全量微调、RLHF",{"path":61,"title":62,"description":63},"\u002Fai\u002Fllm\u002Fintroduction","大模型概述","大语言模型发展历程、核心能力与主流模型对比",{"path":65,"title":66,"description":67},"\u002Fai\u002Fllm\u002Flocal-deploy","本地部署","大模型本地部署：Ollama、vLLM、llama.cpp",{"path":69,"title":70,"description":71},"\u002Fai\u002Fllm\u002Ftransformer","Transformer 架构","Transformer 架构详解：自注意力机制、位置编码、多头注意力",{"path":73,"title":74,"description":75},"\u002Fai\u002Fmcp\u002Fclient","MCP Client 开发","MCP Client 开发指南：连接、调用、集成",{"path":77,"title":78,"description":79},"\u002Fai\u002Fmcp\u002Fdebugging","MCP 调试与排错","MCP Server 开发与集成过程中的常见问题、日志分析、诊断工具",{"path":81,"title":82,"description":83},"\u002Fai\u002Fmcp\u002Fintroduction","MCP 概述","Model Context Protocol 协议概述：架构、核心概念、应用场景",{"path":85,"title":86,"description":87},"\u002Fai\u002Fmcp\u002Fserver","MCP Server 开发","MCP Server 开发指南：资源、工具、提示词的实现",{"path":89,"title":90,"description":91},"\u002Fai\u002Fmcp\u002Ftools","MCP Tools 深入","深入理解 MCP Tools：与 Resources\u002FPrompts 的差异、Schema 设计、Annotations 与权限控制",{"path":93,"title":94,"description":95},"\u002Fai\u002Fprompt\u002Fadvanced","高级 Prompt 模式","高级 Prompt 设计模式：Tree-of-Thought、自我反思、多轮对话策略",{"path":97,"title":98,"description":99},"\u002Fai\u002Fprompt\u002Fbasics","Prompt 基础","Prompt Engineering 入门：基本概念、角色设定、输出格式控制",{"path":101,"title":102,"description":103},"\u002Fai\u002Fprompt\u002Ftechniques","提示词技巧","常用提示词技巧：Few-shot、Chain-of-Thought、ReAct",{"path":105,"title":106,"description":107},"\u002Fai\u002Frag\u002Fembedding","文本嵌入","文本嵌入模型：Embedding 原理、模型选择、相似度计算",{"path":109,"title":110,"description":111},"\u002Fai\u002Frag\u002Fintroduction","RAG 概述","检索增强生成（RAG）架构原理、优势与应用场景",{"path":113,"title":114,"description":115},"\u002Fai\u002Frag\u002Fpractice","RAG 实战","RAG 应用实战：文档问答系统、知识库搭建",{"path":117,"title":118,"description":119},"\u002Fai\u002Frag\u002Fvector-database","向量数据库","主流向量数据库对比：Milvus、Pinecone、Chroma、Weaviate",{"path":121,"title":122,"description":123},"\u002Fai\u002Fskills\u002Fbest-practices","Skill 最佳实践","编写高质量 Skill 的设计原则、常见陷阱与优化技巧",{"path":125,"title":126,"description":127},"\u002Fai\u002Fskills\u002Fcreating","创建自定义 Skill","从零编写一个可被 Agent 自动发现和调用的 Skill",{"path":129,"title":130,"description":131},"\u002Fai\u002Fskills\u002Fintroduction","Agent Skills 概述","Claude Agent Skills 概念、工作原理、与 Tools\u002FMCP 的区别",{"path":133,"title":134,"description":135},"\u002Fgolang\u002Fadvanced\u002Fconcurrency","Go - 并发深入","深入理解 Go 并发编程的核心机制。",{"path":137,"title":138,"description":139},"\u002Fgolang\u002Fadvanced\u002Fgc","Go - 垃圾回收","理解 Go 的垃圾回收机制，掌握 GC 调优方法。",{"path":141,"title":142,"description":143},"\u002Fgolang\u002Fadvanced\u002Fgmp","Go - GMP 调度模型","GMP 是 Go 运行时调度器的核心模型，理解它对于编写高性能 Go 程序至关重要。",{"path":145,"title":146,"description":147},"\u002Fgolang\u002Fadvanced\u002Fgo-concurrency","Go - 并发编程","Go 的并发是其核心特性之一，通过 Goroutine 和 Channel 实现。",{"path":149,"title":150,"description":151},"\u002Fgolang\u002Fadvanced\u002Fmemory","Go - 内存模型","理解 Go 的内存分配机制和内存模型。",{"path":153,"title":154,"description":155},"\u002Fgolang\u002Fadvanced\u002Fprofiling","Go - 性能分析","掌握 Go 的性能分析工具：pprof、trace、benchmark。",{"path":157,"title":158,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-basic","Go - 基础语法",{"path":160,"title":161,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-composite","Go - 复合类型",{"path":163,"title":164,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-control","Go - 流程控制",{"path":166,"title":167,"description":168},"\u002Fgolang\u002Fcore\u002Fgo-error","Go - 错误处理","Go 使用显式的错误返回值来处理错误，而不是异常机制。",{"path":170,"title":171,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-function","Go - 函数",{"path":173,"title":174,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-install","Go - 环境搭建",{"path":176,"title":177,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-interface","Go - 接口",{"path":179,"title":180,"description":181},"\u002Fgolang\u002Fcore\u002Fgo-module","Go - 包管理","Go Modules 是 Go 1.11 引入的官方依赖管理方案，Go 1.16 后成为默认模式。",{"path":183,"title":184,"description":185},"\u002Fgolang\u002Fdistributed\u002Fgrpc","Go - gRPC","gRPC 是 Google 开发的高性能 RPC 框架，使用 Protocol Buffers 作为序列化协议。",{"path":187,"title":188,"description":189},"\u002Fgolang\u002Fdistributed\u002Fmicroservice","Go - 微服务","微服务架构的核心组件：服务发现、负载均衡、熔断降级。",{"path":191,"title":192,"description":193},"\u002Fgolang\u002Fdistributed\u002Fmq","Go - 消息队列","使用 Go 操作 Kafka 和 RabbitMQ。",{"path":195,"title":196,"description":197},"\u002Fgolang\u002Fdistributed\u002Fredis","Go - Redis","使用 go-redis 操作 Redis，实现缓存、分布式锁等功能。",{"path":199,"title":200,"description":201},"\u002Fgolang\u002Fengineering\u002Fconfig","Go - 配置管理","使用 viper 进行配置管理，支持多种配置格式和配置中心。",{"path":203,"title":204,"description":205},"\u002Fgolang\u002Fengineering\u002Fdocker","Go - Docker 部署","使用 Docker 容器化部署 Go 应用。",{"path":207,"title":208,"description":209},"\u002Fgolang\u002Fengineering\u002Fkubernetes","Go - Kubernetes 部署","在 Kubernetes 上部署和管理 Go 应用。",{"path":211,"title":212,"description":213},"\u002Fgolang\u002Fengineering\u002Flogging","Go - 日志系统","使用 zap 和 logrus 构建高性能结构化日志系统。",{"path":215,"title":216,"description":217},"\u002Fgolang\u002Fengineering\u002Ftesting","Go - 单元测试","Go 内置了强大的测试框架，掌握测试是编写高质量代码的基础。",{"path":219,"title":220,"description":221},"\u002Fgolang\u002Fstdlib\u002Fbufio","bufio","在 Go 语言中，bufio 包提供了带缓冲的 I\u002FO 操作，能够提高读写性能。以下是一些常用的 bufio 包 API 及其详细说明：",{"path":223,"title":224,"description":225},"\u002Fgolang\u002Fstdlib\u002Fcontainer","container","在Go语言标准库中，container 包提供了几种常用的数据结构实现，这些数据结构对于高效地管理和操作数据非常有用。以下是 container 包中主要的数据结构：",{"path":227,"title":228,"description":229},"\u002Fgolang\u002Fstdlib\u002Fcrypto","crypto","在 Go 语言中，crypto 包提供了一组用于加密和解密的功能。以下是一些常用的 crypto 包及其子包的 API 及其详细说明：",{"path":231,"title":232,"description":233},"\u002Fgolang\u002Fstdlib\u002Fencoding-csv","encoding\u002Fcsv","在 Go 语言中，encoding\u002Fcsv 包提供了对 CSV（逗号分隔值）文件进行读写的功能。以下是一些常用的 encoding\u002Fcsv 包的 API 及其详细说明：",{"path":235,"title":236,"description":237},"\u002Fgolang\u002Fstdlib\u002Fencoding-json","encoding\u002Fjson","在 Go 语言中，encoding\u002Fjson 包提供了对 JSON 数据进行编码和解码的功能。以下是一些常用的 encoding\u002Fjson 包的 API 及其详细说明：",{"path":239,"title":240,"description":241},"\u002Fgolang\u002Fstdlib\u002Fencoding-xml","encoding\u002Fxml","在 Go 语言中，encoding\u002Fxml 包提供了对 XML 数据进行编码和解码的功能。以下是一些常用的 encoding\u002Fxml 包的 API 及其详细说明：",{"path":243,"title":244,"description":245},"\u002Fgolang\u002Fstdlib\u002Fflag","flag","在Go语言中，flag 包是用于处理命令行参数的标准库，它提供了一种简单而直接的方式来解析和使用命令行参数。下面是关于 flag 包的一些基本介绍和常用功能：",{"path":247,"title":248,"description":249},"\u002Fgolang\u002Fstdlib\u002Ffmt","fmt","在 Go 语言的标准库中，fmt 包是非常重要的，它提供了处理格式化输入和输出的基本工具。以下是一些 fmt 包内常用的API：",{"path":251,"title":252,"description":253},"\u002Fgolang\u002Fstdlib\u002Fhttp","net\u002Fhttp","在 Go 语言中，net\u002Fhttp 包提供了用于构建 HTTP 客户端和服务器的强大工具。以下是一些常用的 net\u002Fhttp 包的 API 及其详细说明：",{"path":255,"title":256,"description":257},"\u002Fgolang\u002Fstdlib\u002Fio","io","在 Go 语言中，io 包提供了基本的输入输出功能。以下是一些常用的 io 包的 API 及其详细说明：",{"path":259,"title":260,"description":261},"\u002Fgolang\u002Fstdlib\u002Flog","log","在 Go 语言中，log 包提供了简单的日志记录功能。以下是一些常用的 log 包的 API 及其详细说明：",{"path":263,"title":264,"description":265},"\u002Fgolang\u002Fstdlib\u002Fmath","math","在 Go 语言中，math 包提供了基本的数学函数和常量。以下是一些常用的 math 包的 API 及其详细说明：",{"path":267,"title":268,"description":11},"\u002Fgolang\u002Fstdlib\u002Fnet","net",{"path":270,"title":271,"description":272},"\u002Fgolang\u002Fstdlib\u002Fos","os","在Go语言中，os 包是一个非常重要且常用的标准库，它提供了与操作系统交互的功能，包括文件操作、环境变量管理、进程管理等。下面是一些 os 包中常用的功能和API：",{"path":274,"title":275,"description":276},"\u002Fgolang\u002Fstdlib\u002Fsort","order","在 Go 语言中，sort 包提供了对切片和用户定义的集合进行排序的函数。它实现了常见的排序算法，如快速排序（Quicksort）和堆排序（Heapsort），并且为自定义集合提供了接口，使得用户可以根据特定的需求进行排序。",{"path":278,"title":279,"description":280},"\u002Fgolang\u002Fstdlib\u002Fstrconv","strconv","在 Go 语言中，strconv 包提供了字符串和基本数据类型之间的转换函数，例如将整数转换为字符串、字符串转换为整数，以及其他类型之间的转换。这些功能非常有用，特别是在处理用户输入或从外部数据源读取数据时。",{"path":282,"title":283,"description":284},"\u002Fgolang\u002Fstdlib\u002Ftime","time","在 Go 语言中，time 包提供了处理时间和日期的功能。以下是一些常用的 time 包的 API 及其详细说明：",{"path":286,"title":287,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Ferror","Gin - 错误处理",{"path":289,"title":290,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Ffile","Gin - 文件处理",{"path":292,"title":293,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Fmiddleware","Gin - 中间件",{"path":295,"title":296,"description":297},"\u002Fgolang\u002Fweb\u002Fgin\u002Fquickstart","Gin - 快速开始","Gin 是目前最流行的 Go Web 框架，以高性能和简洁 API 著称。",{"path":299,"title":300,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Frequest","Gin - 请求处理",{"path":302,"title":303,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Fresponse","Gin - 响应处理",{"path":305,"title":306,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Frouter","Gin - 路由",{"path":308,"title":309,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Fvalidation","Gin - 参数校验",{"path":311,"title":312,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fassociation","GORM - 关联关系",{"path":314,"title":315,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fcrud","GORM - CRUD 操作",{"path":317,"title":318,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fmodel","GORM - 模型定义",{"path":320,"title":321,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fperformance","GORM - 日志与性能",{"path":323,"title":324,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fquery","GORM - 高级查询",{"path":326,"title":327,"description":328},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fquickstart","GORM - 快速开始","GORM 是 Go 语言最流行的 ORM 库，功能强大，使用简单。",{"path":330,"title":331,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Ftransaction","GORM - 事务与 Hook",{"path":333,"title":334,"description":335},"\u002Finterview\u002Fbasic","计算机基础面经","本章节汇总了面试中常见的通用技术概念，不局限于特定语言或数据库，是考察技术内功的关键考点。",{"path":337,"title":338,"description":339},"\u002Finterview\u002Fgolang","Golang 面试题","Go 语言面试高频考点，覆盖基础语法、数据结构、并发编程、内存管理、GC、调度器等核心知识。",{"path":341,"title":342,"description":343},"\u002Finterview\u002Fk8s","Kubernetes 面试题","Kubernetes（K8s）面试高频考点，覆盖架构原理、核心资源、网络存储、调度策略、运维监控等核心知识。",{"path":345,"title":346,"description":347},"\u002Finterview\u002Fmysql","MySQL 面试题","MySQL 数据库面试高频考点，覆盖索引、事务、锁、优化、主从复制等核心知识。",{"path":349,"title":350,"description":351},"\u002Finterview\u002Fredis","Redis 面试题","Redis 面试高频考点，覆盖数据结构、持久化、集群、缓存一致性、性能优化等核心知识。",{"path":353,"title":354,"description":355},"\u002Finterview\u002Frocketmq","RocketMQ 面试题","RocketMQ 面试高频考点，覆盖消息模型、可靠性、顺序消息、事务消息、存储与高可用等核心知识。",{"path":357,"title":358,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Flist-arraylist","List - ArrayList 源码解析",{"path":360,"title":361,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Flist-linkedlist","List - LinkedList 源码解析",{"path":363,"title":364,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Flist-stack","List - Satck源码解析",{"path":366,"title":367,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Flist-vectore","List - Vector 源码解析",{"path":369,"title":370,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fmap-hashmap","Map - HashMap 源码解析",{"path":372,"title":373,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fmap-linkedhashmap","Map - LinkedHashMap 源码解析",{"path":375,"title":376,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fmap-treemap","Map - TreeMap 源码解析",{"path":378,"title":379,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fqueue-deque","Queue - Deque 接口解析",{"path":381,"title":382,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fqueue-queue","Queue - Queue 接口解析",{"path":384,"title":385,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fset-hashset","Set - HashSet源码解析",{"path":387,"title":388,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fset-linkedhashset","Set - LinkedHashSet 源码解析",{"path":390,"title":391,"description":392},"\u002Fother\u002Fjava\u002Fcollection\u002Fset-treeset","Set - TreeSet源码解析","TreeSet 是一个 Set 集合接口的实现类，与 HashSet 类似，其底层也是通过维护了一个 TreeMap 对象来封装了一些实现方法，故本篇不再对 TreeSet 的底层原理进行详细说明，仅对常用 API 做简单介绍，如需了解 TreeMap 的底层实现原理，请移步 Map - HashMap 源码解析",{"path":394,"title":395,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fannotation","Java核心 - 注解",{"path":397,"title":398,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fbasic-grammar","Java核心 - 基础语法",{"path":400,"title":401,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fclass-and-object","Java核心 - 面向对象",{"path":403,"title":404,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fcommon-classes","Java核心 - 常用类",{"path":406,"title":407,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fexception","Java核心 - 异常处理",{"path":409,"title":410,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fgenerics","Java核心 - 泛型",{"path":412,"title":413,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fjdk-env-path","Java核心 - 环境搭建",{"path":415,"title":416,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Freflection","Java核心 - 反射",{"path":418,"title":419,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fstring","Java核心 - String 字符串",{"path":421,"title":422,"description":423},"\u002Fother\u002Fjava\u002Fio\u002Fbuffer-stream","Java IO - 缓冲流","缓冲流是对基本流的包装，通过内置缓冲区减少系统调用次数，大幅提升读写效率。",{"path":425,"title":426,"description":427},"\u002Fother\u002Fjava\u002Fio\u002Fbyte-stream","Java IO - 字节流","字节流是 Java IO 中最基本的流类型，以字节（byte）为单位进行数据读写，可以处理任意类型的文件。",{"path":429,"title":430,"description":431},"\u002Fother\u002Fjava\u002Fio\u002Fchar-stream","Java IO - 字符流","字符流以字符为单位进行读写，专门用于处理文本文件。相比字节流，字符流能够正确处理字符编码，避免中文乱码问题。",{"path":433,"title":434,"description":11},"\u002Fother\u002Fjava\u002Fio\u002Ffile","Java IO - File 类",{"path":436,"title":437,"description":11},"\u002Fother\u002Fjava\u002Fio\u002Fio-stream-system","Java IO - IO流概述",{"path":439,"title":440,"description":441},"\u002Fother\u002Fjava\u002Fio\u002Fnio","Java IO - NIO","NIO（New IO）是 JDK 1.4 引入的新 IO 模型，提供了更高效的 IO 操作方式，支持非阻塞 IO 和多路复用。",{"path":443,"title":444,"description":445},"\u002Fother\u002Fjava\u002Fjvm\u002Fclass-loading","类加载机制","类加载机制是 JVM 将 .class 文件加载到内存，并对数据进行校验、转换解析和初始化，最终形成可被 JVM 直接使用的 Java 类型的过程。",{"path":447,"title":448,"description":449},"\u002Fother\u002Fjava\u002Fjvm\u002Fgarbage-collection","垃圾回收","垃圾回收（Garbage Collection，GC）是 JVM 自动管理内存的机制，负责回收不再使用的对象所占用的内存。",{"path":451,"title":452,"description":453},"\u002Fother\u002Fjava\u002Fjvm\u002Fjvm-memory","JVM 内存结构","JVM 在执行 Java 程序时，会把它管理的内存划分为若干个不同的数据区域。这些区域有各自的用途、创建和销毁时间。",{"path":455,"title":456,"description":457},"\u002Fother\u002Fjava\u002Fjvm\u002Fjvm-tuning","JVM 调优","JVM 调优是优化 Java 应用性能的重要手段，主要包括参数配置、性能监控和问题排查。",{"path":459,"title":460,"description":461},"\u002Fother\u002Fjava\u002Fthread\u002Fatomic","原子类","Java 原子类（Atomic Classes）提供了一种无锁的线程安全方式，基于 CAS（Compare-And-Swap）操作实现。",{"path":463,"title":464,"description":465},"\u002Fother\u002Fjava\u002Fthread\u002Fcompletable-future","CompletableFuture","CompletableFuture 是 JDK 8 引入的异步编程工具，实现了 Future 和 CompletionStage 接口，支持函数式编程和链式调用。",{"path":467,"title":468,"description":469},"\u002Fother\u002Fjava\u002Fthread\u002Fconcurrent-collections","并发集合","Java 并发包提供了多种线程安全的集合类，用于替代传统的同步集合（如 Collections.synchronizedList）。",{"path":471,"title":472,"description":473},"\u002Fother\u002Fjava\u002Fthread\u002Fconcurrent-utils","并发工具类","Java 并发包提供了多种实用的并发工具类，用于控制线程之间的协调与同步。",{"path":475,"title":476,"description":11},"\u002Fother\u002Fjava\u002Fthread\u002Fsynchronized-lock","同步机制",{"path":478,"title":479,"description":11},"\u002Fother\u002Fjava\u002Fthread\u002Fthread-basic","线程基础",{"path":481,"title":482,"description":11},"\u002Fother\u002Fjava\u002Fthread\u002Fthread-pool","线程池",{"path":484,"title":485,"description":486},"\u002Fother\u002Fspring-series\u002Fspring\u002Fannotations-beans","Spring - 基于注解管理Bean","从 Java 5 开始，Java 增加了对注解（Annotation）的支持，它是代码中的一种特殊标记，可以在编译、类加载和运行时被读取，执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下，在源代码中嵌入补充信息。",{"path":488,"title":489,"description":490},"\u002Fother\u002Fspring-series\u002Fspring\u002Fimplement-ioc","Spring - 原理手写IoC","Spring 框架的 IOC 是基于 Java 反射机制实现的，在学习手写 IoC 之前，你需要具备一定的 Java 反射相关的知识，参考本站内的 Java 教程。",{"path":492,"title":493,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fintroduction-case","Spring - 入门案例",{"path":495,"title":496,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-aop","Spring - 面向切面AOP",{"path":498,"title":499,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-aot","Spring - AOT提前编译",{"path":501,"title":502,"description":503},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-data-validation","Spring - 数据校验","在开发中，我们经常遇到参数校验的需求，比如用户注册的时候，要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。如果使用普通方式，我们会把校验的代码和真正的业务处理逻辑耦合在一起，而且如果未来要新增一种校验逻辑也需要在修改多个地方。而spring validation允许通过注解的方式来定义对象校验规则，把校验和业务逻辑分离开，让代码编写更加方便。Spring Validation其实就是对Hibernate Validator进一步的封装，方便在Spring中使用。",{"path":505,"title":506,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-i18n","Spring - 国际化i18n",{"path":508,"title":509,"description":510},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-ioc","Spring - IOC容器","IoC 是 Inversion of Control 的简写，译为“控制反转”，它不是一门技术，而是一种设计思想，是一个重要的面向对象编程法则，能够指导我们如何设计出松耦合、更优良的程序。",{"path":512,"title":513,"description":514},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-junit","Spring - 单元测试JUnit","在之前的测试方法中，几乎都能看到以下的两行代码：",{"path":516,"title":517,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-resources","Spring - 资源操作",{"path":519,"title":520,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-summarize","Spring - Spring概述",{"path":522,"title":523,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-transaction","Spring - 事务",{"path":525,"title":526,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fxml-beans","Spring - 基于XML管理Bean",{"path":528,"title":529,"description":11},"\u002Fother\u002Fspring-series\u002Fspringboot\u002Fspringboot-config","SpringBoot - 配置详解",{"path":531,"title":532,"description":11},"\u002Fother\u002Fspring-series\u002Fspringboot\u002Fspringboot-data","SpringBoot - 数据访问",{"path":534,"title":535,"description":11},"\u002Fother\u002Fspring-series\u002Fspringboot\u002Fspringboot-quickstart","SpringBoot - 快速入门",{"path":537,"title":538,"description":11},"\u002Fother\u002Fspring-series\u002Fspringboot\u002Fspringboot-web","SpringBoot - Web 开发",{"path":540,"title":541,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-config","SpringCloud - 配置中心",{"path":543,"title":544,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-discovery","SpringCloud - 服务注册与发现",{"path":546,"title":547,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-feign","SpringCloud - 服务调用",{"path":549,"title":550,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-gateway","SpringCloud - 服务网关",{"path":552,"title":553,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-introduction","SpringCloud - 微服务概述",{"path":555,"title":556,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-sentinel","SpringCloud - 服务保护",{"path":558,"title":559,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-databind","SpringMVC - 数据绑定与转换",{"path":561,"title":562,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-exception","SpringMVC - 异常处理",{"path":564,"title":565,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-interceptor","SpringMVC - 拦截器",{"path":567,"title":568,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-introduction","SpringMVC - 简介与环境搭建",{"path":570,"title":571,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-request","SpringMVC - 请求处理",{"path":573,"title":574,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-response","SpringMVC - 响应处理",{"path":576,"title":577,"description":578},"\u002Fproject\u002Frocket-leaf\u002Farchitecture","项目架构","Rocket-Leaf 的目录结构、模块划分、数据流向，以及各层之间的依赖关系。",{"path":580,"title":581,"description":582},"\u002Fproject\u002Frocket-leaf\u002Fbackend-layers","后端分层设计","Rocket-Leaf 的 model \u002F rocketmq \u002F service 三层结构，以及服务之间的依赖关系与设计取舍。",{"path":584,"title":585,"description":586},"\u002Fproject\u002Frocket-leaf\u002Fclient-manager","RocketMQ 客户端管理器","AdminClientManager 的多客户端池、默认连接懒加载、自动重连重试的设计与实现。",{"path":588,"title":589,"description":590},"\u002Fproject\u002Frocket-leaf\u002Fencryption","连接信息加密存储","AES-256-GCM + SHA-256 字段级派生密钥的实现，以及如何在不破坏兼容性的前提下为历史明文数据做透明迁移。",{"path":592,"title":593,"description":594},"\u002Fproject\u002Frocket-leaf\u002Ffrontend","前端结构与类型绑定","React + Vite 目录组织、自动生成的 Wails 绑定、api 薄封装与自定义 hooks 的职责划分。",{"path":596,"title":597,"description":598},"\u002Fproject\u002Frocket-leaf","项目简介","Rocket-Leaf 是一款基于 Wails v3 构建的跨平台 RocketMQ 桌面管理客户端，Go 后端 + React 前端。本文档系列拆解它的架构与关键实现。",{"path":600,"title":601,"description":602},"\u002Fproject\u002Frocket-leaf\u002Fwails-v3","Wails v3 入门","Wails v3 的核心概念、Service 绑定机制，以及 Rocket-Leaf 是如何用它把 Go 后端和 React 前端打通的。",{"path":604,"title":605,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-basic","Docker - 入门基础",{"path":607,"title":608,"description":609},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-compose","Docker - Compose","在部署应用时，常常使用到不止一个容器，那么在部署容器的时候就需要一个一个进行部署，这样的部署过程也相对来说比较繁琐复杂，也容易出问题，那么有没有一种更为简单的方法呢？",{"path":611,"title":612,"description":613},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-container-connection","Docker - 容器互联","在上一个章节中我们学习了 Docker 容器的端口映射，可以将 Docker 容器和本地以及网络中的端口进行连接起来。",{"path":615,"title":616,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-dockerfile","Docker - Dockerfile",{"path":618,"title":619,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-helloworld","Docker - HelloWorld",{"path":621,"title":622,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-install","Docker - 安装",{"path":624,"title":625,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-introduce","Docker - 简介",{"path":627,"title":628,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-object","Docker - 镜像、容器、仓库",{"path":630,"title":631,"description":632},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-warehouse","Docker - 仓库管理","仓库是集中存放资源的地方，代码仓库是存放代码的，那么Docker 中的仓库就是存放 Docker 镜像的。",{"path":634,"title":635,"description":636},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-web-containers","Docker - WEB应用实例","在之前的章节中，仅对普通容器进行了演示，但在实际中常常使用到 Docker 容器中的 WEB 应用程序。",{"path":638,"title":639,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-config","Kubernetes - ConfigMap 与 Secret",{"path":641,"title":642,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-helm","Kubernetes - Helm 包管理",{"path":644,"title":645,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-install","Kubernetes - 集群安装",{"path":647,"title":648,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-introduction","Kubernetes - 简介与架构",{"path":650,"title":651,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-kubectl","Kubernetes - kubectl 命令行工具",{"path":653,"title":654,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-monitoring","Kubernetes - 监控与日志",{"path":656,"title":657,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-network-security","Kubernetes - 网络与安全",{"path":659,"title":660,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-service","Kubernetes - Service 与 Ingress",{"path":662,"title":663,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-storage","Kubernetes - 持久化存储",{"path":665,"title":666,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-workload","Kubernetes - 工作负载资源",{"path":668,"title":669,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-bash","Linux - Bash 基础语法",{"path":671,"title":672,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-file-directory","Linux - 文件与目录操作",{"path":674,"title":675,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-network","Linux - 网络配置",{"path":677,"title":678,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-package","Linux - 软件包管理",{"path":680,"title":681,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-process","Linux - 进程管理",{"path":683,"title":684,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-scripts","Linux - 常用脚本示例",{"path":686,"title":687,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-service","Linux - 服务管理",{"path":689,"title":690,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-user-permission","Linux - 用户与权限管理",{"path":692,"title":693,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-https","Nginx - HTTPS 配置",{"path":695,"title":696,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-install","Nginx - 安装与配置",{"path":698,"title":699,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-loadbalance","Nginx - 负载均衡",{"path":701,"title":702,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-optimization","Nginx - 性能优化",{"path":704,"title":705,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-proxy","Nginx - 反向代理",{"path":707,"title":708,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-static","Nginx - 静态资源服务",{"path":710,"title":711,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-vhost","Nginx - 虚拟主机配置",{"path":713,"title":714,"description":715},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fmysql-architecture","MySQL 高可用架构","主从复制、读写分离、分库分表。",{"path":717,"title":718,"description":719},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fmysql-index","MySQL 索引","索引是帮助 MySQL 高效获取数据的有序数据结构。",{"path":721,"title":722,"description":723},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fmysql-lock","MySQL 锁","锁用于解决并发访问时的数据一致性问题。",{"path":725,"title":726,"description":727},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fmysql-optimize","MySQL 性能优化","SQL 优化是后端开发必备技能。",{"path":729,"title":730,"description":731},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fmysql-transaction","MySQL 事务","事务是一组不可分割的操作，要么全部成功，要么全部失败。",{"path":733,"title":734,"description":735},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fsql-advanced","SQL 进阶","多表查询、子查询、函数、视图、存储过程。",{"path":737,"title":738,"description":739},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fsql-basic","SQL 基础","SQL（Structured Query Language）是操作关系型数据库的标准语言。",{"path":741,"title":742,"description":743},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-advanced","Redis 进阶功能","事务、发布订阅、Lua 脚本、Pipeline。",{"path":745,"title":746,"description":747},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-basic","Redis 基础","Redis 安装配置与基本命令。",{"path":749,"title":750,"description":751},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-cluster","Redis 高可用","主从复制、哨兵、Cluster 集群。",{"path":753,"title":754,"description":755},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-datatype","Redis 数据类型","Redis 5 种基本数据类型 + 4 种特殊类型。",{"path":757,"title":758,"description":759},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-optimize","Redis 性能优化","内存优化、缓存问题、最佳实践。",{"path":761,"title":762,"description":763},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-persistence","Redis 持久化","Redis 提供 RDB 和 AOF 两种持久化方式。",{"path":765,"title":766,"description":767},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-principle","Redis 底层原理","数据结构、线程模型、网络模型。",{"path":769,"title":770,"description":771},"\u002Ftutorials\u002Fdev-idea\u002Fdesign-patterns\u002Fbehaiver-patterns\u002Fobserver-pattern","观察者模式","观察者模式属于行为型模式，定义了对象之间的一对多的依赖关系，在这种模式中，当一个对象的状态发生变化时，所有依赖于它的对象都会得到通知，并且执行相关操作。观察者模式又被成为“发布—订阅模式”，即发布者发生改变后，会通知所有订阅者。",{"path":773,"title":774,"description":11},"\u002Ftutorials\u002Fdev-idea\u002Fdesign-patterns\u002Fcreate-patterns\u002Ffactory-pattern","工厂模式",{"path":776,"title":777,"description":778},"\u002Ftutorials\u002Fdev-idea\u002Fdesign-patterns\u002Fcreate-patterns\u002Fsingleton-pattern","单例模式","单例模式是最常用的设计模式之一，他可以保证在整个应用中，某个类只存在一个实例化对象，即全局使用到该类的只有一个对象，这种模式在需要限制某些类的实例数量时非常有用，通常全局只需要一个该对象即可，如一些配置文件映射对象、数据库连接对象等。",{"path":780,"title":781,"description":782},"\u002Ftutorials\u002Fdev-idea\u002Fdesign-patterns\u002Fstructural-patterns\u002Fadapter-pattern","适配器模式","适配器模式是一种结构型模式，可以将一个类的接口转换成客户端所期望的另一种接口，适配器模式可以帮助开发人员在不修改现有代码的情况下，将不兼容的类组合在一起。",{"path":784,"title":785,"description":786},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-basic-operations","Git 创建版本库","在 Git 上创建版本库有两种方式，一种是直接拷贝远程 Git 仓库到本地，另外一种是我们自己创建本地的版本库。",{"path":788,"title":789,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-branch-manage","Git 分支管理",{"path":791,"title":792,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-content-operations","Git 仓库内容操作",{"path":794,"title":795,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-introduce-install","Git 介绍和安装",{"path":797,"title":798,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-remote-manage","Git 远程管理",{"path":800,"title":801,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-workspace-index-repo","Git 工作原理",{"path":803,"title":804,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fhomebrew","HomeBrew 教程",{"path":806,"title":807,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fidea\u002Fshortcuts","快捷键",{"path":809,"title":810,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fmaven\u002Fintroduce-install-config","Maven - 介绍、安装、配置",{"path":812,"title":813,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fbasic-knowledge","2. 基础知识",{"path":815,"title":816,"description":817},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fcomponent-communication","9. 组件通信","在前面的章节内，介绍了 Vue 中最核心的内容——组件的介绍和使用，和 Java 等编程语言相反，组件并不近似于这些变成语言中的类，类可以通过类或者其实例化的对象来相互交互，但 Vue 组件之间的作用域是相互独立的，这就意味着不同组件之间的数据无法相互引用。",{"path":819,"title":820,"description":821},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fcomputed","4. 计算属性","虽然直接在模板中使用表达式方便，但是如果在模板中添加很多逻辑，会让模板变的臃肿且难维护，耦合度较高。有没有一种简单的方式来实现呢？答案是有的。",{"path":823,"title":824,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fcreate-vue-project","1. 环境搭建及安装",{"path":826,"title":827,"description":828},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Flife-cycle","6. 生命周期","生命周期是指组件从创建、挂载、更新到销毁的整个过程中所经历的一系列阶段。在 Vue 中，每个组件都有自己的生命周期，可以通过生命周期钩子函数来监听和处理组件在不同阶段的行为和状态。",{"path":830,"title":831,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fother-api","10. 其他 API",{"path":833,"title":834,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fpinia","8. Pinia",{"path":836,"title":837,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Frouter","7. 路由",{"path":839,"title":840,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Ftemplate-grammar","3. 指令及模板语法",{"path":842,"title":843,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fvue3-new-component","11. Vue3 新组件",{"path":845,"title":846,"description":847},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fwatch","5. 监视","Watch 是 Vue 提供的一个用于监视响应式数据变化并执行相应操作的 API，能够对响应式数据的变化做出一些操作的功能。Vue3 中的 Watch 支持多种用法，包括监视响应式对象、ref 对象、数组、函数等。",{"path":849,"title":850,"description":11},"\u002Ftutorials\u002Fmq\u002Fkafka\u002Fkafka-introduction","Kafka 简介与安装",{"path":852,"title":853,"description":11},"\u002Ftutorials\u002Fmq\u002Fkafka\u002Fkafka-producer-consumer","Kafka 生产者与消费者",{"path":855,"title":856,"description":857},"\u002Ftutorials\u002Fmq\u002Fkafka\u002Fkafka-springboot","Spring Boot 整合 Kafka","Spring Kafka 提供了对 Apache Kafka 的便捷集成。",{"path":859,"title":860,"description":861},"\u002Ftutorials\u002Fmq\u002Frabbitmq\u002Frabbitmq-exchange","RabbitMQ Exchange 详解","Exchange（交换机）是 RabbitMQ 的核心组件，负责接收生产者发送的消息，并根据规则将消息路由到一个或多个队列。",{"path":863,"title":864,"description":11},"\u002Ftutorials\u002Fmq\u002Frabbitmq\u002Frabbitmq-introduction","RabbitMQ 简介与安装",{"path":866,"title":867,"description":868},"\u002Ftutorials\u002Fmq\u002Frabbitmq\u002Frabbitmq-reliability","RabbitMQ 消息可靠性","消息可靠性是消息队列的核心要求，RabbitMQ 提供了多种机制来保证消息不丢失。",{"path":870,"title":871,"description":872},"\u002Ftutorials\u002Fmq\u002Frabbitmq\u002Frabbitmq-springboot","Spring Boot 整合 RabbitMQ","Spring AMQP 提供了对 RabbitMQ 的便捷集成，大大简化了开发工作。",{"path":874,"title":875,"description":11},"\u002Ftutorials\u002Fmq\u002Frocketmq\u002Frocketmq-client","RocketMQ 客户端使用",{"path":877,"title":878,"description":11},"\u002Ftutorials\u002Fmq\u002Frocketmq\u002Frocketmq-concepts","RocketMQ 核心概念",{"path":880,"title":881,"description":11},"\u002Ftutorials\u002Fmq\u002Frocketmq\u002Frocketmq-installation","RocketMQ 安装部署",{"path":883,"title":884,"description":885},"\u002Ftutorials\u002Fmq\u002Frocketmq\u002Frocketmq-message-type","RocketMQ 消息类型","RocketMQ 支持多种消息类型，满足不同业务场景需求。",{"id":887,"title":338,"body":888,"description":339,"extension":13193,"meta":13194,"navigation":1180,"path":337,"seo":13195,"stem":13196,"__hash__":13197},"docs\u002Finterview\u002Fgolang.md",{"type":889,"value":890,"toc":13070},"minimark",[891,894,897,902,907,1038,1049,1051,1055,1111,1278,1280,1284,1289,1311,1316,1405,1410,1421,1426,1551,1553,1557,1562,1573,1661,1666,1678,1680,1684,1744,1749,1760,1762,1766,1771,1816,1951,1960,1962,1966,1971,2030,2035,2046,2048,2052,2057,2118,2128,2178,2180,2184,2189,2219,2224,2405,2410,2453,2455,2459,2625,2627,2631,2637,2709,2715,2828,2830,2834,2891,2896,2916,2918,2922,3110,3115,3129,3131,3135,3139,3183,3187,3209,3214,3280,3282,3286,3291,3345,3350,3435,3440,3451,3453,3457,3462,3518,3601,3603,3607,3614,3679,3686,3688,3692,3696,3774,3779,3790,3795,3803,3805,3809,3829,3831,3835,3840,3929,3933,3943,3988,3992,4005,4119,4123,4140,4142,4146,4151,4256,4258,4262,4271,4314,4319,4366,4368,4372,4376,4477,4479,4483,4563,4565,4569,4574,4585,4590,4601,4607,4609,4613,4619,4623,4709,4714,4734,4736,4740,4746,4819,4821,4825,4830,4872,4874,4878,4940,4942,4946,4951,4954,4959,4978,5008,5010,5014,5081,5083,5087,5176,5178,5182,5187,5227,5232,5246,5248,5252,5257,5298,5386,5391,5393,5397,5402,5440,5446,5448,5452,5457,5528,5533,5590,5595,5603,5608,5638,5640,5644,5649,5759,5765,5770,5783,5785,5789,5865,5867,5871,5876,5978,5983,5988,6045,6047,6051,6071,6076,6102,6107,6173,6178,6455,6460,6480,6482,6486,6491,6603,6608,6613,6631,6633,6637,6642,6653,6658,6753,6755,6759,6764,6789,6825,6827,6831,6835,6840,6888,6893,6907,6912,6920,6922,6926,6931,6957,6959,6963,6968,6979,6981,6985,6990,6995,7009,7014,7016,7020,7024,7029,7040,7045,7062,7068,7070,7074,7079,7088,7126,7128,7132,7137,7142,7163,7168,7188,7231,7233,7237,7242,7268,7274,7276,7280,7284,7289,7294,7314,7319,7333,7339,7341,7345,7392,7433,7435,7439,7444,7450,7453,7455,7459,7494,7496,7500,7504,7509,7595,7600,7620,7622,7626,7631,7754,7760,7762,7766,7938,7940,7944,8045,8047,8051,8090,8179,8181,8185,8189,8194,8322,8326,8332,8334,8338,8496,8501,8509,8511,8515,8520,8740,8742,8746,8795,8797,8801,9003,9009,9011,9015,9082,9088,9090,9094,9099,9119,9124,9270,9272,9276,9280,9285,9399,9404,9418,9420,9424,9429,9435,9439,9559,9564,9584,9586,9590,9851,9853,9857,9862,10031,10033,10037,10043,10045,10049,10242,10244,10248,10252,10257,10329,10331,10335,10403,10408,10512,10514,10518,10523,10723,10725,10729,10734,10788,10793,10975,10977,10981,10985,10990,11040,11045,11175,11177,11181,11275,11280,11294,11296,11300,11373,11377,11391,11393,11397,11402,11420,11425,11445,11451,11453,11457,11501,11562,11564,11568,11572,11577,11699,11704,11706,11710,11782,11784,11788,12041,12043,12047,12148,12153,12202,12204,12208,12212,12218,12220,12224,12616,12618,12622,12627,12663,12840,12842,12846,12918,12920,12924,12927,12976,12979,13024,13027,13066],[892,893,339],"p",{},[895,896],"hr",{},[898,899,901],"h2",{"id":900},"一基础语法","一、基础语法",[903,904,906],"h3",{"id":905},"q1-go-有哪些基本数据类型","Q1: Go 有哪些基本数据类型？",[908,909,910,924],"table",{},[911,912,913],"thead",{},[914,915,916,921],"tr",{},[917,918,920],"th",{"align":919},"left","分类",[917,922,923],{"align":919},"类型",[925,926,927,939,962,987,1000,1013,1023],"tbody",{},[914,928,929,933],{},[930,931,932],"td",{"align":919},"布尔",[930,934,935],{"align":919},[936,937,938],"code",{},"bool",[914,940,941,944],{},[930,942,943],{"align":919},"整型",[930,945,946,949,950,949,953,949,956,949,959],{"align":919},[936,947,948],{},"int",", ",[936,951,952],{},"int8",[936,954,955],{},"int16",[936,957,958],{},"int32",[936,960,961],{},"int64",[914,963,964,967],{},[930,965,966],{"align":919},"无符号",[930,968,969,949,972,949,975,949,978,949,981,949,984],{"align":919},[936,970,971],{},"uint",[936,973,974],{},"uint8",[936,976,977],{},"uint16",[936,979,980],{},"uint32",[936,982,983],{},"uint64",[936,985,986],{},"uintptr",[914,988,989,992],{},[930,990,991],{"align":919},"浮点",[930,993,994,949,997],{"align":919},[936,995,996],{},"float32",[936,998,999],{},"float64",[914,1001,1002,1005],{},[930,1003,1004],{"align":919},"复数",[930,1006,1007,949,1010],{"align":919},[936,1008,1009],{},"complex64",[936,1011,1012],{},"complex128",[914,1014,1015,1018],{},[930,1016,1017],{"align":919},"字符串",[930,1019,1020],{"align":919},[936,1021,1022],{},"string",[914,1024,1025,1028],{},[930,1026,1027],{"align":919},"字符",[930,1029,1030,1033,1034,1037],{"align":919},[936,1031,1032],{},"byte"," (uint8), ",[936,1035,1036],{},"rune"," (int32)",[892,1039,1040,1041,1045,1046,1048],{},"> ",[1042,1043,1044],"strong",{},"注意","：",[936,1047,948],{}," 的大小取决于操作系统（32位系统是int32，64位是int64）。",[895,1050],{},[903,1052,1054],{"id":1053},"q2-go中new和make的区别","Q2: Go中new和make的区别",[908,1056,1057,1070],{},[911,1058,1059],{},[914,1060,1061,1064,1067],{},[917,1062,1063],{"align":919},"特性",[917,1065,1066],{"align":919},"new",[917,1068,1069],{"align":919},"make",[925,1071,1072,1089,1100],{},[914,1073,1074,1077,1083],{},[930,1075,1076],{"align":919},"返回类型",[930,1078,1079,1080],{"align":919},"返回指针 ",[936,1081,1082],{},"*T",[930,1084,1085,1086],{"align":919},"返回值 ",[936,1087,1088],{},"T",[914,1090,1091,1094,1097],{},[930,1092,1093],{"align":919},"初始化",[930,1095,1096],{"align":919},"零值",[930,1098,1099],{"align":919},"初始化内部结构",[914,1101,1102,1105,1108],{},[930,1103,1104],{"align":919},"适用类型",[930,1106,1107],{"align":919},"所有类型",[930,1109,1110],{"align":919},"slice、map、channel",[1112,1113,1117],"pre",{"className":1114,"code":1115,"language":1116,"meta":11,"style":11},"language-go shiki shiki-themes github-light github-light github-dark","\u002F\u002F new - 分配内存，返回指针，零值初始化\np := new(int)       \u002F\u002F *int，值为 0\ns := new([]int)     \u002F\u002F *[]int，值为 nil\n\n\u002F\u002F make - 分配并初始化内部结构\nslice := make([]int, 0, 10)     \u002F\u002F []int，已初始化\nm := make(map[string]int)       \u002F\u002F map，已初始化\nch := make(chan int, 5)         \u002F\u002F chan，已初始化\n","go",[936,1118,1119,1128,1154,1175,1182,1188,1219,1249],{"__ignoreMap":11},[1120,1121,1124],"span",{"class":1122,"line":1123},"line",1,[1120,1125,1127],{"class":1126},"sCsY4","\u002F\u002F new - 分配内存，返回指针，零值初始化\n",[1120,1129,1131,1135,1139,1143,1146,1148,1151],{"class":1122,"line":1130},2,[1120,1132,1134],{"class":1133},"sxrX7","p ",[1120,1136,1138],{"class":1137},"s8jYJ",":=",[1120,1140,1142],{"class":1141},"snPdu"," new",[1120,1144,1145],{"class":1133},"(",[1120,1147,948],{"class":1137},[1120,1149,1150],{"class":1133},")       ",[1120,1152,1153],{"class":1126},"\u002F\u002F *int，值为 0\n",[1120,1155,1157,1160,1162,1164,1167,1169,1172],{"class":1122,"line":1156},3,[1120,1158,1159],{"class":1133},"s ",[1120,1161,1138],{"class":1137},[1120,1163,1142],{"class":1141},[1120,1165,1166],{"class":1133},"([]",[1120,1168,948],{"class":1137},[1120,1170,1171],{"class":1133},")     ",[1120,1173,1174],{"class":1126},"\u002F\u002F *[]int，值为 nil\n",[1120,1176,1178],{"class":1122,"line":1177},4,[1120,1179,1181],{"emptyLinePlaceholder":1180},true,"\n",[1120,1183,1185],{"class":1122,"line":1184},5,[1120,1186,1187],{"class":1126},"\u002F\u002F make - 分配并初始化内部结构\n",[1120,1189,1191,1194,1196,1199,1201,1203,1205,1209,1211,1214,1216],{"class":1122,"line":1190},6,[1120,1192,1193],{"class":1133},"slice ",[1120,1195,1138],{"class":1137},[1120,1197,1198],{"class":1141}," make",[1120,1200,1166],{"class":1133},[1120,1202,948],{"class":1137},[1120,1204,949],{"class":1133},[1120,1206,1208],{"class":1207},"sBjJW","0",[1120,1210,949],{"class":1133},[1120,1212,1213],{"class":1207},"10",[1120,1215,1171],{"class":1133},[1120,1217,1218],{"class":1126},"\u002F\u002F []int，已初始化\n",[1120,1220,1222,1225,1227,1229,1231,1234,1237,1239,1242,1244,1246],{"class":1122,"line":1221},7,[1120,1223,1224],{"class":1133},"m ",[1120,1226,1138],{"class":1137},[1120,1228,1198],{"class":1141},[1120,1230,1145],{"class":1133},[1120,1232,1233],{"class":1137},"map",[1120,1235,1236],{"class":1133},"[",[1120,1238,1022],{"class":1137},[1120,1240,1241],{"class":1133},"]",[1120,1243,948],{"class":1137},[1120,1245,1150],{"class":1133},[1120,1247,1248],{"class":1126},"\u002F\u002F map，已初始化\n",[1120,1250,1252,1255,1257,1259,1261,1264,1267,1269,1272,1275],{"class":1122,"line":1251},8,[1120,1253,1254],{"class":1133},"ch ",[1120,1256,1138],{"class":1137},[1120,1258,1198],{"class":1141},[1120,1260,1145],{"class":1133},[1120,1262,1263],{"class":1137},"chan",[1120,1265,1266],{"class":1137}," int",[1120,1268,949],{"class":1133},[1120,1270,1271],{"class":1207},"5",[1120,1273,1274],{"class":1133},")         ",[1120,1276,1277],{"class":1126},"\u002F\u002F chan，已初始化\n",[895,1279],{},[903,1281,1283],{"id":1282},"q3-go的defer原理是什么","Q3: Go的defer原理是什么",[892,1285,1286],{},[1042,1287,1288],{},"defer 特点：",[1290,1291,1292,1299,1305],"ol",{},[1293,1294,1295,1298],"li",{},[1042,1296,1297],{},"延迟执行","：函数返回前执行",[1293,1300,1301,1304],{},[1042,1302,1303],{},"LIFO 顺序","：后进先出（栈结构）",[1293,1306,1307,1310],{},[1042,1308,1309],{},"参数预计算","：声明时求值，非执行时",[892,1312,1313],{},[1042,1314,1315],{},"底层实现：",[1112,1317,1319],{"className":1114,"code":1318,"language":1116,"meta":11,"style":11},"type _defer struct {\n    siz     int32    \u002F\u002F 参数大小\n    started bool\n    sp      uintptr  \u002F\u002F 栈指针\n    pc      uintptr  \u002F\u002F 程序计数器\n    fn      *funcval \u002F\u002F 延迟函数\n    link    *_defer  \u002F\u002F 链表指针\n}\n",[936,1320,1321,1335,1345,1353,1363,1373,1387,1400],{"__ignoreMap":11},[1120,1322,1323,1326,1329,1332],{"class":1122,"line":1123},[1120,1324,1325],{"class":1137},"type",[1120,1327,1328],{"class":1141}," _defer",[1120,1330,1331],{"class":1137}," struct",[1120,1333,1334],{"class":1133}," {\n",[1120,1336,1337,1340,1342],{"class":1122,"line":1130},[1120,1338,1339],{"class":1133},"    siz     ",[1120,1341,958],{"class":1137},[1120,1343,1344],{"class":1126},"    \u002F\u002F 参数大小\n",[1120,1346,1347,1350],{"class":1122,"line":1156},[1120,1348,1349],{"class":1133},"    started ",[1120,1351,1352],{"class":1137},"bool\n",[1120,1354,1355,1358,1360],{"class":1122,"line":1177},[1120,1356,1357],{"class":1133},"    sp      ",[1120,1359,986],{"class":1137},[1120,1361,1362],{"class":1126},"  \u002F\u002F 栈指针\n",[1120,1364,1365,1368,1370],{"class":1122,"line":1184},[1120,1366,1367],{"class":1133},"    pc      ",[1120,1369,986],{"class":1137},[1120,1371,1372],{"class":1126},"  \u002F\u002F 程序计数器\n",[1120,1374,1375,1378,1381,1384],{"class":1122,"line":1190},[1120,1376,1377],{"class":1133},"    fn      ",[1120,1379,1380],{"class":1137},"*",[1120,1382,1383],{"class":1141},"funcval",[1120,1385,1386],{"class":1126}," \u002F\u002F 延迟函数\n",[1120,1388,1389,1392,1394,1397],{"class":1122,"line":1221},[1120,1390,1391],{"class":1133},"    link    ",[1120,1393,1380],{"class":1137},[1120,1395,1396],{"class":1141},"_defer",[1120,1398,1399],{"class":1126},"  \u002F\u002F 链表指针\n",[1120,1401,1402],{"class":1122,"line":1251},[1120,1403,1404],{"class":1133},"}\n",[892,1406,1407],{},[1042,1408,1409],{},"执行时机：",[1290,1411,1412,1415,1418],{},[1293,1413,1414],{},"函数 return 值赋给返回变量",[1293,1416,1417],{},"执行 defer 函数（LIFO）",[1293,1419,1420],{},"函数返回",[892,1422,1423],{},[1042,1424,1425],{},"经典陷阱：",[1112,1427,1429],{"className":1114,"code":1428,"language":1116,"meta":11,"style":11},"\u002F\u002F 情况一：返回值是匿名变量\nfunc f1() int {\n    x := 5\n    defer func() { x++ }()\n    return x  \u002F\u002F 返回 5（x 的副本）\n}\n\n\u002F\u002F 情况二：返回值是命名变量\nfunc f2() (x int) {\n    defer func() { x++ }()\n    return 5  \u002F\u002F 返回 6（defer 修改了命名返回值）\n}\n",[936,1430,1431,1436,1451,1461,1478,1489,1493,1497,1502,1522,1535,1546],{"__ignoreMap":11},[1120,1432,1433],{"class":1122,"line":1123},[1120,1434,1435],{"class":1126},"\u002F\u002F 情况一：返回值是匿名变量\n",[1120,1437,1438,1441,1444,1447,1449],{"class":1122,"line":1130},[1120,1439,1440],{"class":1137},"func",[1120,1442,1443],{"class":1141}," f1",[1120,1445,1446],{"class":1133},"() ",[1120,1448,948],{"class":1137},[1120,1450,1334],{"class":1133},[1120,1452,1453,1456,1458],{"class":1122,"line":1156},[1120,1454,1455],{"class":1133},"    x ",[1120,1457,1138],{"class":1137},[1120,1459,1460],{"class":1207}," 5\n",[1120,1462,1463,1466,1469,1472,1475],{"class":1122,"line":1177},[1120,1464,1465],{"class":1137},"    defer",[1120,1467,1468],{"class":1137}," func",[1120,1470,1471],{"class":1133},"() { x",[1120,1473,1474],{"class":1137},"++",[1120,1476,1477],{"class":1133}," }()\n",[1120,1479,1480,1483,1486],{"class":1122,"line":1184},[1120,1481,1482],{"class":1137},"    return",[1120,1484,1485],{"class":1133}," x  ",[1120,1487,1488],{"class":1126},"\u002F\u002F 返回 5（x 的副本）\n",[1120,1490,1491],{"class":1122,"line":1190},[1120,1492,1404],{"class":1133},[1120,1494,1495],{"class":1122,"line":1221},[1120,1496,1181],{"emptyLinePlaceholder":1180},[1120,1498,1499],{"class":1122,"line":1251},[1120,1500,1501],{"class":1126},"\u002F\u002F 情况二：返回值是命名变量\n",[1120,1503,1505,1507,1510,1513,1517,1519],{"class":1122,"line":1504},9,[1120,1506,1440],{"class":1137},[1120,1508,1509],{"class":1141}," f2",[1120,1511,1512],{"class":1133},"() (",[1120,1514,1516],{"class":1515},"sP4rz","x",[1120,1518,1266],{"class":1137},[1120,1520,1521],{"class":1133},") {\n",[1120,1523,1525,1527,1529,1531,1533],{"class":1122,"line":1524},10,[1120,1526,1465],{"class":1137},[1120,1528,1468],{"class":1137},[1120,1530,1471],{"class":1133},[1120,1532,1474],{"class":1137},[1120,1534,1477],{"class":1133},[1120,1536,1538,1540,1543],{"class":1122,"line":1537},11,[1120,1539,1482],{"class":1137},[1120,1541,1542],{"class":1207}," 5",[1120,1544,1545],{"class":1126},"  \u002F\u002F 返回 6（defer 修改了命名返回值）\n",[1120,1547,1549],{"class":1122,"line":1548},12,[1120,1550,1404],{"class":1133},[895,1552],{},[903,1554,1556],{"id":1555},"q4-go的select可以用于什么","Q4: Go的select可以用于什么",[892,1558,1559],{},[1042,1560,1561],{},"用途：",[1290,1563,1564,1567,1570],{},[1293,1565,1566],{},"多路 Channel 复用",[1293,1568,1569],{},"超时控制",[1293,1571,1572],{},"非阻塞操作",[1112,1574,1576],{"className":1114,"code":1575,"language":1116,"meta":11,"style":11},"select {\ncase msg := \u003C-ch1:\n    \u002F\u002F 处理 ch1\ncase ch2 \u003C- x:\n    \u002F\u002F 发送到 ch2\ncase \u003C-time.After(time.Second):\n    \u002F\u002F 超时处理\ndefault:\n    \u002F\u002F 非阻塞（所有 case 不满足时执行）\n}\n",[936,1577,1578,1585,1601,1606,1619,1624,1639,1644,1652,1657],{"__ignoreMap":11},[1120,1579,1580,1583],{"class":1122,"line":1123},[1120,1581,1582],{"class":1137},"select",[1120,1584,1334],{"class":1133},[1120,1586,1587,1590,1593,1595,1598],{"class":1122,"line":1130},[1120,1588,1589],{"class":1137},"case",[1120,1591,1592],{"class":1133}," msg ",[1120,1594,1138],{"class":1137},[1120,1596,1597],{"class":1137}," \u003C-",[1120,1599,1600],{"class":1133},"ch1:\n",[1120,1602,1603],{"class":1122,"line":1156},[1120,1604,1605],{"class":1126},"    \u002F\u002F 处理 ch1\n",[1120,1607,1608,1610,1613,1616],{"class":1122,"line":1177},[1120,1609,1589],{"class":1137},[1120,1611,1612],{"class":1133}," ch2 ",[1120,1614,1615],{"class":1137},"\u003C-",[1120,1617,1618],{"class":1133}," x:\n",[1120,1620,1621],{"class":1122,"line":1184},[1120,1622,1623],{"class":1126},"    \u002F\u002F 发送到 ch2\n",[1120,1625,1626,1628,1630,1633,1636],{"class":1122,"line":1190},[1120,1627,1589],{"class":1137},[1120,1629,1597],{"class":1137},[1120,1631,1632],{"class":1133},"time.",[1120,1634,1635],{"class":1141},"After",[1120,1637,1638],{"class":1133},"(time.Second):\n",[1120,1640,1641],{"class":1122,"line":1221},[1120,1642,1643],{"class":1126},"    \u002F\u002F 超时处理\n",[1120,1645,1646,1649],{"class":1122,"line":1251},[1120,1647,1648],{"class":1137},"default",[1120,1650,1651],{"class":1133},":\n",[1120,1653,1654],{"class":1122,"line":1504},[1120,1655,1656],{"class":1126},"    \u002F\u002F 非阻塞（所有 case 不满足时执行）\n",[1120,1658,1659],{"class":1122,"line":1524},[1120,1660,1404],{"class":1133},[892,1662,1663],{},[1042,1664,1665],{},"特点：",[1667,1668,1669,1672,1675],"ul",{},[1293,1670,1671],{},"随机选择就绪的 case（避免饥饿）",[1293,1673,1674],{},"没有 default 时会阻塞",[1293,1676,1677],{},"case 必须是 Channel 操作",[895,1679],{},[903,1681,1683],{"id":1682},"q5-go值接收者和指针接收者的区别","Q5: Go值接收者和指针接收者的区别",[908,1685,1686,1698],{},[911,1687,1688],{},[914,1689,1690,1692,1695],{},[917,1691,1063],{"align":919},[917,1693,1694],{"align":919},"值接收者",[917,1696,1697],{"align":919},"指针接收者",[925,1699,1700,1711,1722,1733],{},[914,1701,1702,1705,1708],{},[930,1703,1704],{"align":919},"调用时",[930,1706,1707],{"align":919},"复制整个值",[930,1709,1710],{"align":919},"只复制指针",[914,1712,1713,1716,1719],{},[930,1714,1715],{"align":919},"修改原值",[930,1717,1718],{"align":919},"不可以",[930,1720,1721],{"align":919},"可以",[914,1723,1724,1727,1730],{},[930,1725,1726],{"align":919},"nil 接收者",[930,1728,1729],{"align":919},"无法调用（panic）",[930,1731,1732],{"align":919},"可以调用",[914,1734,1735,1738,1741],{},[930,1736,1737],{"align":919},"接口实现",[930,1739,1740],{"align":919},"T 和 *T 都实现",[930,1742,1743],{"align":919},"只有 *T 实现",[892,1745,1746],{},[1042,1747,1748],{},"选择建议：",[1667,1750,1751,1754,1757],{},[1293,1752,1753],{},"需要修改接收者 → 指针接收者",[1293,1755,1756],{},"大结构体 → 指针接收者（避免复制开销）",[1293,1758,1759],{},"一致性 → 同一类型保持统一风格",[895,1761],{},[903,1763,1765],{"id":1764},"q6-go的struct能不能比较","Q6: Go的Struct能不能比较",[892,1767,1768],{},[1042,1769,1770],{},"能否比较取决于字段类型：",[908,1772,1773,1783],{},[911,1774,1775],{},[914,1776,1777,1780],{},[917,1778,1779],{"align":919},"可比较类型",[917,1781,1782],{"align":919},"不可比较类型",[925,1784,1785,1793,1800,1808],{},[914,1786,1787,1790],{},[930,1788,1789],{"align":919},"基本类型（int、string、bool）",[930,1791,1792],{"align":919},"slice",[914,1794,1795,1798],{},[930,1796,1797],{"align":919},"指针",[930,1799,1233],{"align":919},[914,1801,1802,1805],{},[930,1803,1804],{"align":919},"数组（元素可比较）",[930,1806,1807],{"align":919},"function",[914,1809,1810,1813],{},[930,1811,1812],{"align":919},"接口（动态类型和值都可比较）",[930,1814,1815],{"align":919},"包含不可比较字段的结构体",[1112,1817,1819],{"className":1114,"code":1818,"language":1116,"meta":11,"style":11},"type Person struct {\n    Name string\n    Age  int\n}\np1 := Person{\"Tom\", 18}\np2 := Person{\"Tom\", 18}\nfmt.Println(p1 == p2)  \u002F\u002F true ✅\n\ntype Data struct {\n    Values []int  \u002F\u002F 包含 slice\n}\n\u002F\u002F d1 == d2  \u002F\u002F 编译错误！❌\n",[936,1820,1821,1832,1840,1848,1852,1875,1894,1914,1918,1929,1939,1943],{"__ignoreMap":11},[1120,1822,1823,1825,1828,1830],{"class":1122,"line":1123},[1120,1824,1325],{"class":1137},[1120,1826,1827],{"class":1141}," Person",[1120,1829,1331],{"class":1137},[1120,1831,1334],{"class":1133},[1120,1833,1834,1837],{"class":1122,"line":1130},[1120,1835,1836],{"class":1133},"    Name ",[1120,1838,1839],{"class":1137},"string\n",[1120,1841,1842,1845],{"class":1122,"line":1156},[1120,1843,1844],{"class":1133},"    Age  ",[1120,1846,1847],{"class":1137},"int\n",[1120,1849,1850],{"class":1122,"line":1177},[1120,1851,1404],{"class":1133},[1120,1853,1854,1857,1859,1861,1864,1868,1870,1873],{"class":1122,"line":1184},[1120,1855,1856],{"class":1133},"p1 ",[1120,1858,1138],{"class":1137},[1120,1860,1827],{"class":1141},[1120,1862,1863],{"class":1133},"{",[1120,1865,1867],{"class":1866},"sIIMD","\"Tom\"",[1120,1869,949],{"class":1133},[1120,1871,1872],{"class":1207},"18",[1120,1874,1404],{"class":1133},[1120,1876,1877,1880,1882,1884,1886,1888,1890,1892],{"class":1122,"line":1190},[1120,1878,1879],{"class":1133},"p2 ",[1120,1881,1138],{"class":1137},[1120,1883,1827],{"class":1141},[1120,1885,1863],{"class":1133},[1120,1887,1867],{"class":1866},[1120,1889,949],{"class":1133},[1120,1891,1872],{"class":1207},[1120,1893,1404],{"class":1133},[1120,1895,1896,1899,1902,1905,1908,1911],{"class":1122,"line":1221},[1120,1897,1898],{"class":1133},"fmt.",[1120,1900,1901],{"class":1141},"Println",[1120,1903,1904],{"class":1133},"(p1 ",[1120,1906,1907],{"class":1137},"==",[1120,1909,1910],{"class":1133}," p2)  ",[1120,1912,1913],{"class":1126},"\u002F\u002F true ✅\n",[1120,1915,1916],{"class":1122,"line":1251},[1120,1917,1181],{"emptyLinePlaceholder":1180},[1120,1919,1920,1922,1925,1927],{"class":1122,"line":1504},[1120,1921,1325],{"class":1137},[1120,1923,1924],{"class":1141}," Data",[1120,1926,1331],{"class":1137},[1120,1928,1334],{"class":1133},[1120,1930,1931,1934,1936],{"class":1122,"line":1524},[1120,1932,1933],{"class":1133},"    Values []",[1120,1935,948],{"class":1137},[1120,1937,1938],{"class":1126},"  \u002F\u002F 包含 slice\n",[1120,1940,1941],{"class":1122,"line":1537},[1120,1942,1404],{"class":1133},[1120,1944,1945,1948],{"class":1122,"line":1548},[1120,1946,1947],{"class":1126},"\u002F\u002F d1 == d2",[1120,1949,1950],{"class":1126},"  \u002F\u002F 编译错误！❌\n",[892,1952,1953,1956,1957],{},[1042,1954,1955],{},"深度比较："," 使用 ",[936,1958,1959],{},"reflect.DeepEqual()",[895,1961],{},[903,1963,1965],{"id":1964},"q7-go函数返回局部变量的指针是否安全","Q7: Go函数返回局部变量的指针是否安全",[892,1967,1968],{},[1042,1969,1970],{},"安全！Go 的逃逸分析会处理。",[1112,1972,1974],{"className":1114,"code":1973,"language":1116,"meta":11,"style":11},"func createUser() *User {\n    u := User{Name: \"Tom\"}  \u002F\u002F 逃逸到堆\n    return &u               \u002F\u002F 安全返回\n}\n",[936,1975,1976,1992,2013,2026],{"__ignoreMap":11},[1120,1977,1978,1980,1983,1985,1987,1990],{"class":1122,"line":1123},[1120,1979,1440],{"class":1137},[1120,1981,1982],{"class":1141}," createUser",[1120,1984,1446],{"class":1133},[1120,1986,1380],{"class":1137},[1120,1988,1989],{"class":1141},"User",[1120,1991,1334],{"class":1133},[1120,1993,1994,1997,1999,2002,2005,2007,2010],{"class":1122,"line":1130},[1120,1995,1996],{"class":1133},"    u ",[1120,1998,1138],{"class":1137},[1120,2000,2001],{"class":1141}," User",[1120,2003,2004],{"class":1133},"{Name: ",[1120,2006,1867],{"class":1866},[1120,2008,2009],{"class":1133},"}  ",[1120,2011,2012],{"class":1126},"\u002F\u002F 逃逸到堆\n",[1120,2014,2015,2017,2020,2023],{"class":1122,"line":1156},[1120,2016,1482],{"class":1137},[1120,2018,2019],{"class":1137}," &",[1120,2021,2022],{"class":1133},"u               ",[1120,2024,2025],{"class":1126},"\u002F\u002F 安全返回\n",[1120,2027,2028],{"class":1122,"line":1177},[1120,2029,1404],{"class":1133},[892,2031,2032],{},[1042,2033,2034],{},"原理：",[1667,2036,2037,2040,2043],{},[1293,2038,2039],{},"编译器进行逃逸分析",[1293,2041,2042],{},"需要逃逸的变量分配在堆上",[1293,2044,2045],{},"堆上的变量由 GC 管理",[895,2047],{},[903,2049,2051],{"id":2050},"q8-go中两个nil可能不相等吗","Q8: Go中两个Nil可能不相等吗",[892,2053,2054],{},[1042,2055,2056],{},"可能！接口类型的 nil 判断有陷阱。",[1112,2058,2060],{"className":1114,"code":2059,"language":1116,"meta":11,"style":11},"var p *int = nil\nvar i interface{} = p\nfmt.Println(i == nil)  \u002F\u002F false! ❌\n",[936,2061,2062,2079,2098],{"__ignoreMap":11},[1120,2063,2064,2067,2070,2073,2076],{"class":1122,"line":1123},[1120,2065,2066],{"class":1137},"var",[1120,2068,2069],{"class":1133}," p ",[1120,2071,2072],{"class":1137},"*int",[1120,2074,2075],{"class":1137}," =",[1120,2077,2078],{"class":1207}," nil\n",[1120,2080,2081,2083,2086,2089,2092,2095],{"class":1122,"line":1130},[1120,2082,2066],{"class":1137},[1120,2084,2085],{"class":1133}," i ",[1120,2087,2088],{"class":1137},"interface",[1120,2090,2091],{"class":1133},"{} ",[1120,2093,2094],{"class":1137},"=",[1120,2096,2097],{"class":1133}," p\n",[1120,2099,2100,2102,2104,2107,2109,2112,2115],{"class":1122,"line":1156},[1120,2101,1898],{"class":1133},[1120,2103,1901],{"class":1141},[1120,2105,2106],{"class":1133},"(i ",[1120,2108,1907],{"class":1137},[1120,2110,2111],{"class":1207}," nil",[1120,2113,2114],{"class":1133},")  ",[1120,2116,2117],{"class":1126},"\u002F\u002F false! ❌\n",[892,2119,2120,2123,2124,2127],{},[1042,2121,2122],{},"原因："," 接口由 ",[936,2125,2126],{},"(type, value)"," 组成，只有两者都为 nil 才等于 nil。",[1112,2129,2131],{"className":1114,"code":2130,"language":1116,"meta":11,"style":11},"type eface struct {\n    _type *_type         \u002F\u002F 类型：*int（非 nil）\n    data  unsafe.Pointer \u002F\u002F 值：nil\n}\n",[936,2132,2133,2144,2157,2174],{"__ignoreMap":11},[1120,2134,2135,2137,2140,2142],{"class":1122,"line":1123},[1120,2136,1325],{"class":1137},[1120,2138,2139],{"class":1141}," eface",[1120,2141,1331],{"class":1137},[1120,2143,1334],{"class":1133},[1120,2145,2146,2149,2151,2154],{"class":1122,"line":1130},[1120,2147,2148],{"class":1133},"    _type ",[1120,2150,1380],{"class":1137},[1120,2152,2153],{"class":1141},"_type",[1120,2155,2156],{"class":1126},"         \u002F\u002F 类型：*int（非 nil）\n",[1120,2158,2159,2162,2165,2168,2171],{"class":1122,"line":1156},[1120,2160,2161],{"class":1133},"    data  ",[1120,2163,2164],{"class":1141},"unsafe",[1120,2166,2167],{"class":1133},".",[1120,2169,2170],{"class":1141},"Pointer",[1120,2172,2173],{"class":1126}," \u002F\u002F 值：nil\n",[1120,2175,2176],{"class":1122,"line":1177},[1120,2177,1404],{"class":1133},[895,2179],{},[903,2181,2183],{"id":2182},"q9-go-的-error-处理机制","Q9: Go 的 error 处理机制",[892,2185,2186],{},[1042,2187,2188],{},"error 是一个接口：",[1112,2190,2192],{"className":1114,"code":2191,"language":1116,"meta":11,"style":11},"type error interface {\n    Error() string\n}\n",[936,2193,2194,2206,2215],{"__ignoreMap":11},[1120,2195,2196,2198,2201,2204],{"class":1122,"line":1123},[1120,2197,1325],{"class":1137},[1120,2199,2200],{"class":1137}," error",[1120,2202,2203],{"class":1137}," interface",[1120,2205,1334],{"class":1133},[1120,2207,2208,2211,2213],{"class":1122,"line":1130},[1120,2209,2210],{"class":1141},"    Error",[1120,2212,1446],{"class":1133},[1120,2214,1839],{"class":1137},[1120,2216,2217],{"class":1122,"line":1156},[1120,2218,1404],{"class":1133},[892,2220,2221],{},[1042,2222,2223],{},"错误处理方式：",[1112,2225,2227],{"className":1114,"code":2226,"language":1116,"meta":11,"style":11},"\u002F\u002F 1. 直接返回\nif err != nil {\n    return err\n}\n\n\u002F\u002F 2. 包装错误（Go 1.13+）\nif err != nil {\n    return fmt.Errorf(\"读取配置失败: %w\", err)\n}\n\n\u002F\u002F 3. 错误判断\nif errors.Is(err, os.ErrNotExist) {\n    \u002F\u002F 处理文件不存在\n}\n\n\u002F\u002F 4. 类型断言\nvar pathErr *os.PathError\nif errors.As(err, &pathErr) {\n    fmt.Println(pathErr.Path)\n}\n",[936,2228,2229,2234,2249,2256,2260,2264,2269,2281,2305,2309,2313,2318,2331,2337,2342,2347,2353,2370,2389,2400],{"__ignoreMap":11},[1120,2230,2231],{"class":1122,"line":1123},[1120,2232,2233],{"class":1126},"\u002F\u002F 1. 直接返回\n",[1120,2235,2236,2239,2242,2245,2247],{"class":1122,"line":1130},[1120,2237,2238],{"class":1137},"if",[1120,2240,2241],{"class":1133}," err ",[1120,2243,2244],{"class":1137},"!=",[1120,2246,2111],{"class":1207},[1120,2248,1334],{"class":1133},[1120,2250,2251,2253],{"class":1122,"line":1156},[1120,2252,1482],{"class":1137},[1120,2254,2255],{"class":1133}," err\n",[1120,2257,2258],{"class":1122,"line":1177},[1120,2259,1404],{"class":1133},[1120,2261,2262],{"class":1122,"line":1184},[1120,2263,1181],{"emptyLinePlaceholder":1180},[1120,2265,2266],{"class":1122,"line":1190},[1120,2267,2268],{"class":1126},"\u002F\u002F 2. 包装错误（Go 1.13+）\n",[1120,2270,2271,2273,2275,2277,2279],{"class":1122,"line":1221},[1120,2272,2238],{"class":1137},[1120,2274,2241],{"class":1133},[1120,2276,2244],{"class":1137},[1120,2278,2111],{"class":1207},[1120,2280,1334],{"class":1133},[1120,2282,2283,2285,2288,2291,2293,2296,2299,2302],{"class":1122,"line":1251},[1120,2284,1482],{"class":1137},[1120,2286,2287],{"class":1133}," fmt.",[1120,2289,2290],{"class":1141},"Errorf",[1120,2292,1145],{"class":1133},[1120,2294,2295],{"class":1866},"\"读取配置失败: ",[1120,2297,2298],{"class":1207},"%w",[1120,2300,2301],{"class":1866},"\"",[1120,2303,2304],{"class":1133},", err)\n",[1120,2306,2307],{"class":1122,"line":1504},[1120,2308,1404],{"class":1133},[1120,2310,2311],{"class":1122,"line":1524},[1120,2312,1181],{"emptyLinePlaceholder":1180},[1120,2314,2315],{"class":1122,"line":1537},[1120,2316,2317],{"class":1126},"\u002F\u002F 3. 错误判断\n",[1120,2319,2320,2322,2325,2328],{"class":1122,"line":1548},[1120,2321,2238],{"class":1137},[1120,2323,2324],{"class":1133}," errors.",[1120,2326,2327],{"class":1141},"Is",[1120,2329,2330],{"class":1133},"(err, os.ErrNotExist) {\n",[1120,2332,2334],{"class":1122,"line":2333},13,[1120,2335,2336],{"class":1126},"    \u002F\u002F 处理文件不存在\n",[1120,2338,2340],{"class":1122,"line":2339},14,[1120,2341,1404],{"class":1133},[1120,2343,2345],{"class":1122,"line":2344},15,[1120,2346,1181],{"emptyLinePlaceholder":1180},[1120,2348,2350],{"class":1122,"line":2349},16,[1120,2351,2352],{"class":1126},"\u002F\u002F 4. 类型断言\n",[1120,2354,2356,2358,2361,2363,2365,2367],{"class":1122,"line":2355},17,[1120,2357,2066],{"class":1137},[1120,2359,2360],{"class":1133}," pathErr ",[1120,2362,1380],{"class":1137},[1120,2364,271],{"class":1141},[1120,2366,2167],{"class":1133},[1120,2368,2369],{"class":1141},"PathError\n",[1120,2371,2373,2375,2377,2380,2383,2386],{"class":1122,"line":2372},18,[1120,2374,2238],{"class":1137},[1120,2376,2324],{"class":1133},[1120,2378,2379],{"class":1141},"As",[1120,2381,2382],{"class":1133},"(err, ",[1120,2384,2385],{"class":1137},"&",[1120,2387,2388],{"class":1133},"pathErr) {\n",[1120,2390,2392,2395,2397],{"class":1122,"line":2391},19,[1120,2393,2394],{"class":1133},"    fmt.",[1120,2396,1901],{"class":1141},[1120,2398,2399],{"class":1133},"(pathErr.Path)\n",[1120,2401,2403],{"class":1122,"line":2402},20,[1120,2404,1404],{"class":1133},[892,2406,2407],{},[1042,2408,2409],{},"errors.Is vs errors.As：",[908,2411,2412,2425],{},[911,2413,2414],{},[914,2415,2416,2419,2422],{},[917,2417,2418],{"align":919},"函数",[917,2420,2421],{"align":919},"作用",[917,2423,2424],{"align":919},"场景",[925,2426,2427,2440],{},[914,2428,2429,2434,2437],{},[930,2430,2431],{"align":919},[936,2432,2433],{},"errors.Is",[930,2435,2436],{"align":919},"判断是否是特定错误值",[930,2438,2439],{"align":919},"sentinel error",[914,2441,2442,2447,2450],{},[930,2443,2444],{"align":919},[936,2445,2446],{},"errors.As",[930,2448,2449],{"align":919},"判断是否是特定错误类型",[930,2451,2452],{"align":919},"自定义 error 类型",[895,2454],{},[903,2456,2458],{"id":2457},"q10-如何自定义-error","Q10: 如何自定义 error",[1112,2460,2462],{"className":1114,"code":2461,"language":1116,"meta":11,"style":11},"\u002F\u002F 方法一：实现 error 接口\ntype MyError struct {\n    Code    int\n    Message string\n}\n\nfunc (e *MyError) Error() string {\n    return fmt.Sprintf(\"[%d] %s\", e.Code, e.Message)\n}\n\n\u002F\u002F 方法二：使用 errors.New\nvar ErrNotFound = errors.New(\"not found\")\n\n\u002F\u002F 方法三：使用 fmt.Errorf\nerr := fmt.Errorf(\"user %d not found\", userID)\n",[936,2463,2464,2469,2480,2487,2494,2498,2502,2529,2557,2561,2565,2570,2592,2596,2601],{"__ignoreMap":11},[1120,2465,2466],{"class":1122,"line":1123},[1120,2467,2468],{"class":1126},"\u002F\u002F 方法一：实现 error 接口\n",[1120,2470,2471,2473,2476,2478],{"class":1122,"line":1130},[1120,2472,1325],{"class":1137},[1120,2474,2475],{"class":1141}," MyError",[1120,2477,1331],{"class":1137},[1120,2479,1334],{"class":1133},[1120,2481,2482,2485],{"class":1122,"line":1156},[1120,2483,2484],{"class":1133},"    Code    ",[1120,2486,1847],{"class":1137},[1120,2488,2489,2492],{"class":1122,"line":1177},[1120,2490,2491],{"class":1133},"    Message ",[1120,2493,1839],{"class":1137},[1120,2495,2496],{"class":1122,"line":1184},[1120,2497,1404],{"class":1133},[1120,2499,2500],{"class":1122,"line":1190},[1120,2501,1181],{"emptyLinePlaceholder":1180},[1120,2503,2504,2506,2509,2512,2514,2517,2520,2523,2525,2527],{"class":1122,"line":1221},[1120,2505,1440],{"class":1137},[1120,2507,2508],{"class":1133}," (",[1120,2510,2511],{"class":1515},"e ",[1120,2513,1380],{"class":1137},[1120,2515,2516],{"class":1141},"MyError",[1120,2518,2519],{"class":1133},") ",[1120,2521,2522],{"class":1141},"Error",[1120,2524,1446],{"class":1133},[1120,2526,1022],{"class":1137},[1120,2528,1334],{"class":1133},[1120,2530,2531,2533,2535,2538,2540,2543,2546,2549,2552,2554],{"class":1122,"line":1251},[1120,2532,1482],{"class":1137},[1120,2534,2287],{"class":1133},[1120,2536,2537],{"class":1141},"Sprintf",[1120,2539,1145],{"class":1133},[1120,2541,2542],{"class":1866},"\"[",[1120,2544,2545],{"class":1207},"%d",[1120,2547,2548],{"class":1866},"] ",[1120,2550,2551],{"class":1207},"%s",[1120,2553,2301],{"class":1866},[1120,2555,2556],{"class":1133},", e.Code, e.Message)\n",[1120,2558,2559],{"class":1122,"line":1504},[1120,2560,1404],{"class":1133},[1120,2562,2563],{"class":1122,"line":1524},[1120,2564,1181],{"emptyLinePlaceholder":1180},[1120,2566,2567],{"class":1122,"line":1537},[1120,2568,2569],{"class":1126},"\u002F\u002F 方法二：使用 errors.New\n",[1120,2571,2572,2574,2577,2579,2581,2584,2586,2589],{"class":1122,"line":1548},[1120,2573,2066],{"class":1137},[1120,2575,2576],{"class":1133}," ErrNotFound ",[1120,2578,2094],{"class":1137},[1120,2580,2324],{"class":1133},[1120,2582,2583],{"class":1141},"New",[1120,2585,1145],{"class":1133},[1120,2587,2588],{"class":1866},"\"not found\"",[1120,2590,2591],{"class":1133},")\n",[1120,2593,2594],{"class":1122,"line":2333},[1120,2595,1181],{"emptyLinePlaceholder":1180},[1120,2597,2598],{"class":1122,"line":2339},[1120,2599,2600],{"class":1126},"\u002F\u002F 方法三：使用 fmt.Errorf\n",[1120,2602,2603,2606,2608,2610,2612,2614,2617,2619,2622],{"class":1122,"line":2344},[1120,2604,2605],{"class":1133},"err ",[1120,2607,1138],{"class":1137},[1120,2609,2287],{"class":1133},[1120,2611,2290],{"class":1141},[1120,2613,1145],{"class":1133},[1120,2615,2616],{"class":1866},"\"user ",[1120,2618,2545],{"class":1207},[1120,2620,2621],{"class":1866}," not found\"",[1120,2623,2624],{"class":1133},", userID)\n",[895,2626],{},[903,2628,2630],{"id":2629},"q11-panic-和-recover-的使用","Q11: panic 和 recover 的使用",[892,2632,2633,2636],{},[1042,2634,2635],{},"panic："," 程序遇到无法恢复的错误时使用",[1112,2638,2640],{"className":1114,"code":2639,"language":1116,"meta":11,"style":11},"\u002F\u002F 触发 panic\npanic(\"something went wrong\")\n\n\u002F\u002F 常见触发场景\narr[100]          \u002F\u002F 数组越界\nnil.Method()      \u002F\u002F nil 指针调用方法\nclose(closedChan) \u002F\u002F 重复关闭 channel\n",[936,2641,2642,2647,2659,2663,2668,2682,2698],{"__ignoreMap":11},[1120,2643,2644],{"class":1122,"line":1123},[1120,2645,2646],{"class":1126},"\u002F\u002F 触发 panic\n",[1120,2648,2649,2652,2654,2657],{"class":1122,"line":1130},[1120,2650,2651],{"class":1141},"panic",[1120,2653,1145],{"class":1133},[1120,2655,2656],{"class":1866},"\"something went wrong\"",[1120,2658,2591],{"class":1133},[1120,2660,2661],{"class":1122,"line":1156},[1120,2662,1181],{"emptyLinePlaceholder":1180},[1120,2664,2665],{"class":1122,"line":1177},[1120,2666,2667],{"class":1126},"\u002F\u002F 常见触发场景\n",[1120,2669,2670,2673,2676,2679],{"class":1122,"line":1184},[1120,2671,2672],{"class":1133},"arr[",[1120,2674,2675],{"class":1207},"100",[1120,2677,2678],{"class":1133},"]          ",[1120,2680,2681],{"class":1126},"\u002F\u002F 数组越界\n",[1120,2683,2684,2687,2689,2692,2695],{"class":1122,"line":1190},[1120,2685,2686],{"class":1207},"nil",[1120,2688,2167],{"class":1133},[1120,2690,2691],{"class":1141},"Method",[1120,2693,2694],{"class":1133},"()      ",[1120,2696,2697],{"class":1126},"\u002F\u002F nil 指针调用方法\n",[1120,2699,2700,2703,2706],{"class":1122,"line":1221},[1120,2701,2702],{"class":1141},"close",[1120,2704,2705],{"class":1133},"(closedChan) ",[1120,2707,2708],{"class":1126},"\u002F\u002F 重复关闭 channel\n",[892,2710,2711,2714],{},[1042,2712,2713],{},"recover："," 捕获 panic，必须在 defer 中使用",[1112,2716,2718],{"className":1114,"code":2717,"language":1116,"meta":11,"style":11},"func safeCall() {\n    defer func() {\n        if r := recover(); r != nil {\n            log.Printf(\"Recovered: %v\", r)\n            \u002F\u002F 打印堆栈\n            debug.PrintStack()\n        }\n    }()\n    \n    \u002F\u002F 可能 panic 的代码\n    riskyOperation()\n}\n",[936,2719,2720,2730,2738,2760,2781,2786,2797,2802,2807,2812,2817,2824],{"__ignoreMap":11},[1120,2721,2722,2724,2727],{"class":1122,"line":1123},[1120,2723,1440],{"class":1137},[1120,2725,2726],{"class":1141}," safeCall",[1120,2728,2729],{"class":1133},"() {\n",[1120,2731,2732,2734,2736],{"class":1122,"line":1130},[1120,2733,1465],{"class":1137},[1120,2735,1468],{"class":1137},[1120,2737,2729],{"class":1133},[1120,2739,2740,2743,2746,2748,2751,2754,2756,2758],{"class":1122,"line":1156},[1120,2741,2742],{"class":1137},"        if",[1120,2744,2745],{"class":1133}," r ",[1120,2747,1138],{"class":1137},[1120,2749,2750],{"class":1141}," recover",[1120,2752,2753],{"class":1133},"(); r ",[1120,2755,2244],{"class":1137},[1120,2757,2111],{"class":1207},[1120,2759,1334],{"class":1133},[1120,2761,2762,2765,2768,2770,2773,2776,2778],{"class":1122,"line":1177},[1120,2763,2764],{"class":1133},"            log.",[1120,2766,2767],{"class":1141},"Printf",[1120,2769,1145],{"class":1133},[1120,2771,2772],{"class":1866},"\"Recovered: ",[1120,2774,2775],{"class":1207},"%v",[1120,2777,2301],{"class":1866},[1120,2779,2780],{"class":1133},", r)\n",[1120,2782,2783],{"class":1122,"line":1184},[1120,2784,2785],{"class":1126},"            \u002F\u002F 打印堆栈\n",[1120,2787,2788,2791,2794],{"class":1122,"line":1190},[1120,2789,2790],{"class":1133},"            debug.",[1120,2792,2793],{"class":1141},"PrintStack",[1120,2795,2796],{"class":1133},"()\n",[1120,2798,2799],{"class":1122,"line":1221},[1120,2800,2801],{"class":1133},"        }\n",[1120,2803,2804],{"class":1122,"line":1251},[1120,2805,2806],{"class":1133},"    }()\n",[1120,2808,2809],{"class":1122,"line":1504},[1120,2810,2811],{"class":1133},"    \n",[1120,2813,2814],{"class":1122,"line":1524},[1120,2815,2816],{"class":1126},"    \u002F\u002F 可能 panic 的代码\n",[1120,2818,2819,2822],{"class":1122,"line":1537},[1120,2820,2821],{"class":1141},"    riskyOperation",[1120,2823,2796],{"class":1133},[1120,2825,2826],{"class":1122,"line":1548},[1120,2827,1404],{"class":1133},[895,2829],{},[903,2831,2833],{"id":2832},"q12-panic-和-error-如何选择","Q12: panic 和 error 如何选择",[908,2835,2836,2848],{},[911,2837,2838],{},[914,2839,2840,2842,2845],{},[917,2841,2424],{"align":919},[917,2843,2844],{"align":919},"选择",[917,2846,2847],{"align":919},"原因",[925,2849,2850,2861,2871,2881],{},[914,2851,2852,2855,2858],{},[930,2853,2854],{"align":919},"预期内的错误",[930,2856,2857],{"align":919},"error",[930,2859,2860],{"align":919},"调用方可处理",[914,2862,2863,2866,2868],{},[930,2864,2865],{"align":919},"编程错误\u002Fbug",[930,2867,2651],{"align":919},[930,2869,2870],{"align":919},"不应该发生",[914,2872,2873,2876,2878],{},[930,2874,2875],{"align":919},"初始化失败",[930,2877,2651],{"align":919},[930,2879,2880],{"align":919},"程序无法继续",[914,2882,2883,2886,2888],{},[930,2884,2885],{"align":919},"库函数",[930,2887,2857],{"align":919},[930,2889,2890],{"align":919},"不应强制终止程序",[892,2892,2893],{},[1042,2894,2895],{},"原则：",[1667,2897,2898,2904,2910],{},[1293,2899,2900,2903],{},[1042,2901,2902],{},"优先用 error","：Go 推荐显式错误处理",[1293,2905,2906,2909],{},[1042,2907,2908],{},"panic 慎用","：只用于真正的异常情况",[1293,2911,2912,2915],{},[1042,2913,2914],{},"库代码不要 panic","：让调用方决定如何处理",[895,2917],{},[903,2919,2921],{"id":2920},"q13-deferpanicrecover-的执行顺序","Q13: defer、panic、recover 的执行顺序",[1112,2923,2925],{"className":1114,"code":2924,"language":1116,"meta":11,"style":11},"func main() {\n    defer fmt.Println(\"1\")\n    defer fmt.Println(\"2\")\n    \n    defer func() {\n        if r := recover(); r != nil {\n            fmt.Println(\"Recovered:\", r)\n        }\n    }()\n    \n    defer fmt.Println(\"3\")\n    \n    panic(\"error!\")\n    \n    defer fmt.Println(\"4\")  \u002F\u002F 不会执行\n}\n\n\u002F\u002F 输出：\n\u002F\u002F 3\n\u002F\u002F Recovered: error!\n\u002F\u002F 2\n\u002F\u002F 1\n",[936,2926,2927,2936,2951,2966,2970,2978,2996,3010,3014,3018,3022,3037,3041,3053,3057,3075,3079,3083,3088,3093,3098,3104],{"__ignoreMap":11},[1120,2928,2929,2931,2934],{"class":1122,"line":1123},[1120,2930,1440],{"class":1137},[1120,2932,2933],{"class":1141}," main",[1120,2935,2729],{"class":1133},[1120,2937,2938,2940,2942,2944,2946,2949],{"class":1122,"line":1130},[1120,2939,1465],{"class":1137},[1120,2941,2287],{"class":1133},[1120,2943,1901],{"class":1141},[1120,2945,1145],{"class":1133},[1120,2947,2948],{"class":1866},"\"1\"",[1120,2950,2591],{"class":1133},[1120,2952,2953,2955,2957,2959,2961,2964],{"class":1122,"line":1156},[1120,2954,1465],{"class":1137},[1120,2956,2287],{"class":1133},[1120,2958,1901],{"class":1141},[1120,2960,1145],{"class":1133},[1120,2962,2963],{"class":1866},"\"2\"",[1120,2965,2591],{"class":1133},[1120,2967,2968],{"class":1122,"line":1177},[1120,2969,2811],{"class":1133},[1120,2971,2972,2974,2976],{"class":1122,"line":1184},[1120,2973,1465],{"class":1137},[1120,2975,1468],{"class":1137},[1120,2977,2729],{"class":1133},[1120,2979,2980,2982,2984,2986,2988,2990,2992,2994],{"class":1122,"line":1190},[1120,2981,2742],{"class":1137},[1120,2983,2745],{"class":1133},[1120,2985,1138],{"class":1137},[1120,2987,2750],{"class":1141},[1120,2989,2753],{"class":1133},[1120,2991,2244],{"class":1137},[1120,2993,2111],{"class":1207},[1120,2995,1334],{"class":1133},[1120,2997,2998,3001,3003,3005,3008],{"class":1122,"line":1221},[1120,2999,3000],{"class":1133},"            fmt.",[1120,3002,1901],{"class":1141},[1120,3004,1145],{"class":1133},[1120,3006,3007],{"class":1866},"\"Recovered:\"",[1120,3009,2780],{"class":1133},[1120,3011,3012],{"class":1122,"line":1251},[1120,3013,2801],{"class":1133},[1120,3015,3016],{"class":1122,"line":1504},[1120,3017,2806],{"class":1133},[1120,3019,3020],{"class":1122,"line":1524},[1120,3021,2811],{"class":1133},[1120,3023,3024,3026,3028,3030,3032,3035],{"class":1122,"line":1537},[1120,3025,1465],{"class":1137},[1120,3027,2287],{"class":1133},[1120,3029,1901],{"class":1141},[1120,3031,1145],{"class":1133},[1120,3033,3034],{"class":1866},"\"3\"",[1120,3036,2591],{"class":1133},[1120,3038,3039],{"class":1122,"line":1548},[1120,3040,2811],{"class":1133},[1120,3042,3043,3046,3048,3051],{"class":1122,"line":2333},[1120,3044,3045],{"class":1141},"    panic",[1120,3047,1145],{"class":1133},[1120,3049,3050],{"class":1866},"\"error!\"",[1120,3052,2591],{"class":1133},[1120,3054,3055],{"class":1122,"line":2339},[1120,3056,2811],{"class":1133},[1120,3058,3059,3061,3063,3065,3067,3070,3072],{"class":1122,"line":2344},[1120,3060,1465],{"class":1137},[1120,3062,2287],{"class":1133},[1120,3064,1901],{"class":1141},[1120,3066,1145],{"class":1133},[1120,3068,3069],{"class":1866},"\"4\"",[1120,3071,2114],{"class":1133},[1120,3073,3074],{"class":1126},"\u002F\u002F 不会执行\n",[1120,3076,3077],{"class":1122,"line":2349},[1120,3078,1404],{"class":1133},[1120,3080,3081],{"class":1122,"line":2355},[1120,3082,1181],{"emptyLinePlaceholder":1180},[1120,3084,3085],{"class":1122,"line":2372},[1120,3086,3087],{"class":1126},"\u002F\u002F 输出：\n",[1120,3089,3090],{"class":1122,"line":2391},[1120,3091,3092],{"class":1126},"\u002F\u002F 3\n",[1120,3094,3095],{"class":1122,"line":2402},[1120,3096,3097],{"class":1126},"\u002F\u002F Recovered: error!\n",[1120,3099,3101],{"class":1122,"line":3100},21,[1120,3102,3103],{"class":1126},"\u002F\u002F 2\n",[1120,3105,3107],{"class":1122,"line":3106},22,[1120,3108,3109],{"class":1126},"\u002F\u002F 1\n",[892,3111,3112],{},[1042,3113,3114],{},"执行流程：",[1290,3116,3117,3120,3123,3126],{},[1293,3118,3119],{},"panic 发生后，停止正常执行",[1293,3121,3122],{},"按 LIFO 顺序执行 defer",[1293,3124,3125],{},"遇到 recover 则捕获 panic",[1293,3127,3128],{},"recover 后续的 defer 继续执行",[895,3130],{},[898,3132,3134],{"id":3133},"二数据结构","二、数据结构",[903,3136,3138],{"id":3137},"q14-string-底层结构是什么","Q14: string 底层结构是什么？",[1112,3140,3142],{"className":1114,"code":3141,"language":1116,"meta":11,"style":11},"type stringStruct struct {\n    str unsafe.Pointer  \u002F\u002F 指向底层字节数组\n    len int             \u002F\u002F 字符串长度（字节数）\n}\n",[936,3143,3144,3155,3169,3179],{"__ignoreMap":11},[1120,3145,3146,3148,3151,3153],{"class":1122,"line":1123},[1120,3147,1325],{"class":1137},[1120,3149,3150],{"class":1141}," stringStruct",[1120,3152,1331],{"class":1137},[1120,3154,1334],{"class":1133},[1120,3156,3157,3160,3162,3164,3166],{"class":1122,"line":1130},[1120,3158,3159],{"class":1133},"    str ",[1120,3161,2164],{"class":1141},[1120,3163,2167],{"class":1133},[1120,3165,2170],{"class":1141},[1120,3167,3168],{"class":1126},"  \u002F\u002F 指向底层字节数组\n",[1120,3170,3171,3174,3176],{"class":1122,"line":1156},[1120,3172,3173],{"class":1133},"    len ",[1120,3175,948],{"class":1137},[1120,3177,3178],{"class":1126},"             \u002F\u002F 字符串长度（字节数）\n",[1120,3180,3181],{"class":1122,"line":1177},[1120,3182,1404],{"class":1133},[892,3184,3185],{},[1042,3186,1665],{},[1667,3188,3189,3196,3202],{},[1293,3190,3191,3192,3195],{},"string 是",[1042,3193,3194],{},"不可变","的",[1293,3197,3198,3201],{},[936,3199,3200],{},"len(s)"," 返回字节数，不是字符数",[1293,3203,3204,3205,3208],{},"使用 ",[936,3206,3207],{},"utf8.RuneCountInString(s)"," 获取字符数",[892,3210,3211],{},[1042,3212,3213],{},"字符串拼接性能对比：",[908,3215,3216,3228],{},[911,3217,3218],{},[914,3219,3220,3223,3226],{},[917,3221,3222],{"align":919},"方式",[917,3224,3225],{"align":919},"性能",[917,3227,2424],{"align":919},[925,3229,3230,3243,3255,3268],{},[914,3231,3232,3237,3240],{},[930,3233,3234],{"align":919},[936,3235,3236],{},"+",[930,3238,3239],{"align":919},"低",[930,3241,3242],{"align":919},"少量拼接",[914,3244,3245,3250,3252],{},[930,3246,3247],{"align":919},[936,3248,3249],{},"fmt.Sprintf",[930,3251,3239],{"align":919},[930,3253,3254],{"align":919},"格式化",[914,3256,3257,3262,3265],{},[930,3258,3259],{"align":919},[936,3260,3261],{},"strings.Builder",[930,3263,3264],{"align":919},"高",[930,3266,3267],{"align":919},"大量拼接（推荐）",[914,3269,3270,3275,3277],{},[930,3271,3272],{"align":919},[936,3273,3274],{},"bytes.Buffer",[930,3276,3264],{"align":919},[930,3278,3279],{"align":919},"需要字节操作",[895,3281],{},[903,3283,3285],{"id":3284},"q15-slice-底层结构和扩容机制","Q15: slice 底层结构和扩容机制",[892,3287,3288],{},[1042,3289,3290],{},"底层结构：",[1112,3292,3294],{"className":1114,"code":3293,"language":1116,"meta":11,"style":11},"type slice struct {\n    array unsafe.Pointer  \u002F\u002F 指向底层数组\n    len   int             \u002F\u002F 当前长度\n    cap   int             \u002F\u002F 容量\n}\n",[936,3295,3296,3307,3321,3331,3341],{"__ignoreMap":11},[1120,3297,3298,3300,3303,3305],{"class":1122,"line":1123},[1120,3299,1325],{"class":1137},[1120,3301,3302],{"class":1141}," slice",[1120,3304,1331],{"class":1137},[1120,3306,1334],{"class":1133},[1120,3308,3309,3312,3314,3316,3318],{"class":1122,"line":1130},[1120,3310,3311],{"class":1133},"    array ",[1120,3313,2164],{"class":1141},[1120,3315,2167],{"class":1133},[1120,3317,2170],{"class":1141},[1120,3319,3320],{"class":1126},"  \u002F\u002F 指向底层数组\n",[1120,3322,3323,3326,3328],{"class":1122,"line":1156},[1120,3324,3325],{"class":1133},"    len   ",[1120,3327,948],{"class":1137},[1120,3329,3330],{"class":1126},"             \u002F\u002F 当前长度\n",[1120,3332,3333,3336,3338],{"class":1122,"line":1177},[1120,3334,3335],{"class":1133},"    cap   ",[1120,3337,948],{"class":1137},[1120,3339,3340],{"class":1126},"             \u002F\u002F 容量\n",[1120,3342,3343],{"class":1122,"line":1184},[1120,3344,1404],{"class":1133},[892,3346,3347],{},[1042,3348,3349],{},"扩容规则（Go 1.18+）：",[1112,3351,3353],{"className":1114,"code":3352,"language":1116,"meta":11,"style":11},"if oldCap \u003C 256 {\n    newCap = oldCap * 2  \u002F\u002F 翻倍\n} else {\n    newCap = oldCap + (oldCap + 3*256) \u002F 4  \u002F\u002F 约 1.25 倍增长\n}\n",[936,3354,3355,3370,3387,3397,3431],{"__ignoreMap":11},[1120,3356,3357,3359,3362,3365,3368],{"class":1122,"line":1123},[1120,3358,2238],{"class":1137},[1120,3360,3361],{"class":1133}," oldCap ",[1120,3363,3364],{"class":1137},"\u003C",[1120,3366,3367],{"class":1207}," 256",[1120,3369,1334],{"class":1133},[1120,3371,3372,3375,3377,3379,3381,3384],{"class":1122,"line":1130},[1120,3373,3374],{"class":1133},"    newCap ",[1120,3376,2094],{"class":1137},[1120,3378,3361],{"class":1133},[1120,3380,1380],{"class":1137},[1120,3382,3383],{"class":1207}," 2",[1120,3385,3386],{"class":1126},"  \u002F\u002F 翻倍\n",[1120,3388,3389,3392,3395],{"class":1122,"line":1156},[1120,3390,3391],{"class":1133},"} ",[1120,3393,3394],{"class":1137},"else",[1120,3396,1334],{"class":1133},[1120,3398,3399,3401,3403,3405,3407,3410,3412,3415,3417,3420,3422,3425,3428],{"class":1122,"line":1177},[1120,3400,3374],{"class":1133},[1120,3402,2094],{"class":1137},[1120,3404,3361],{"class":1133},[1120,3406,3236],{"class":1137},[1120,3408,3409],{"class":1133}," (oldCap ",[1120,3411,3236],{"class":1137},[1120,3413,3414],{"class":1207}," 3",[1120,3416,1380],{"class":1137},[1120,3418,3419],{"class":1207},"256",[1120,3421,2519],{"class":1133},[1120,3423,3424],{"class":1137},"\u002F",[1120,3426,3427],{"class":1207}," 4",[1120,3429,3430],{"class":1126},"  \u002F\u002F 约 1.25 倍增长\n",[1120,3432,3433],{"class":1122,"line":1184},[1120,3434,1404],{"class":1133},[892,3436,3437],{},[1042,3438,3439],{},"注意事项：",[1667,3441,3442,3448],{},[1293,3443,3444,3445],{},"预分配可避免扩容：",[936,3446,3447],{},"make([]int, 0, 100)",[1293,3449,3450],{},"扩容后底层数组可能变化，原切片不受影响",[895,3452],{},[903,3454,3456],{"id":3455},"q16-go中对nil的slice和空slice的处理是一致的吗","Q16: Go中对nil的Slice和空Slice的处理是一致的吗",[892,3458,3459],{},[1042,3460,3461],{},"不完全一致。",[1112,3463,3465],{"className":1114,"code":3464,"language":1116,"meta":11,"style":11},"var nilSlice []int          \u002F\u002F nil slice: nil, len=0, cap=0\nemptySlice := []int{}       \u002F\u002F 空 slice: 非 nil, len=0, cap=0\nemptySlice2 := make([]int, 0) \u002F\u002F 空 slice: 非 nil, len=0, cap=0\n",[936,3466,3467,3479,3497],{"__ignoreMap":11},[1120,3468,3469,3471,3474,3476],{"class":1122,"line":1123},[1120,3470,2066],{"class":1137},[1120,3472,3473],{"class":1133}," nilSlice []",[1120,3475,948],{"class":1137},[1120,3477,3478],{"class":1126},"          \u002F\u002F nil slice: nil, len=0, cap=0\n",[1120,3480,3481,3484,3486,3489,3491,3494],{"class":1122,"line":1130},[1120,3482,3483],{"class":1133},"emptySlice ",[1120,3485,1138],{"class":1137},[1120,3487,3488],{"class":1133}," []",[1120,3490,948],{"class":1137},[1120,3492,3493],{"class":1133},"{}       ",[1120,3495,3496],{"class":1126},"\u002F\u002F 空 slice: 非 nil, len=0, cap=0\n",[1120,3498,3499,3502,3504,3506,3508,3510,3512,3514,3516],{"class":1122,"line":1156},[1120,3500,3501],{"class":1133},"emptySlice2 ",[1120,3503,1138],{"class":1137},[1120,3505,1198],{"class":1141},[1120,3507,1166],{"class":1133},[1120,3509,948],{"class":1137},[1120,3511,949],{"class":1133},[1120,3513,1208],{"class":1207},[1120,3515,2519],{"class":1133},[1120,3517,3496],{"class":1126},[908,3519,3520,3533],{},[911,3521,3522],{},[914,3523,3524,3527,3530],{},[917,3525,3526],{"align":919},"操作",[917,3528,3529],{"align":919},"nil Slice",[917,3531,3532],{"align":919},"空 Slice",[925,3534,3535,3546,3557,3569,3586],{},[914,3536,3537,3542,3544],{},[930,3538,3539],{"align":919},[936,3540,3541],{},"len()",[930,3543,1208],{"align":919},[930,3545,1208],{"align":919},[914,3547,3548,3553,3555],{},[930,3549,3550],{"align":919},[936,3551,3552],{},"cap()",[930,3554,1208],{"align":919},[930,3556,1208],{"align":919},[914,3558,3559,3564,3567],{},[930,3560,3561],{"align":919},[936,3562,3563],{},"append()",[930,3565,3566],{"align":919},"正常",[930,3568,3566],{"align":919},[914,3570,3571,3576,3581],{},[930,3572,3573],{"align":919},[936,3574,3575],{},"== nil",[930,3577,3578],{"align":919},[1042,3579,3580],{},"true",[930,3582,3583],{"align":919},[1042,3584,3585],{},"false",[914,3587,3588,3591,3596],{},[930,3589,3590],{"align":919},"JSON 序列化",[930,3592,3593],{"align":919},[936,3594,3595],{},"null",[930,3597,3598],{"align":919},[936,3599,3600],{},"[]",[895,3602],{},[903,3604,3606],{"id":3605},"q17-slice-作为参数传递会发生什么","Q17: slice 作为参数传递会发生什么",[892,3608,3609,3610,3613],{},"slice 是",[1042,3611,3612],{},"值传递","，但传递的是 header（ptr, len, cap），底层数组共享。",[1112,3615,3617],{"className":1114,"code":3616,"language":1116,"meta":11,"style":11},"func modify(s []int) {\n    s[0] = 100       \u002F\u002F ✅ 会修改原切片\n    s = append(s, 4) \u002F\u002F ❌ 不会影响原切片的 len\n}\n",[936,3618,3619,3637,3654,3675],{"__ignoreMap":11},[1120,3620,3621,3623,3626,3628,3631,3633,3635],{"class":1122,"line":1123},[1120,3622,1440],{"class":1137},[1120,3624,3625],{"class":1141}," modify",[1120,3627,1145],{"class":1133},[1120,3629,3630],{"class":1515},"s",[1120,3632,3488],{"class":1133},[1120,3634,948],{"class":1137},[1120,3636,1521],{"class":1133},[1120,3638,3639,3642,3644,3646,3648,3651],{"class":1122,"line":1130},[1120,3640,3641],{"class":1133},"    s[",[1120,3643,1208],{"class":1207},[1120,3645,2548],{"class":1133},[1120,3647,2094],{"class":1137},[1120,3649,3650],{"class":1207}," 100",[1120,3652,3653],{"class":1126},"       \u002F\u002F ✅ 会修改原切片\n",[1120,3655,3656,3659,3661,3664,3667,3670,3672],{"class":1122,"line":1156},[1120,3657,3658],{"class":1133},"    s ",[1120,3660,2094],{"class":1137},[1120,3662,3663],{"class":1141}," append",[1120,3665,3666],{"class":1133},"(s, ",[1120,3668,3669],{"class":1207},"4",[1120,3671,2519],{"class":1133},[1120,3673,3674],{"class":1126},"\u002F\u002F ❌ 不会影响原切片的 len\n",[1120,3676,3677],{"class":1122,"line":1177},[1120,3678,1404],{"class":1133},[892,3680,3681,3682,3685],{},"如果要修改原切片的长度，需要传指针 ",[936,3683,3684],{},"*[]int","。",[895,3687],{},[903,3689,3691],{"id":3690},"q18-map-的底层实现","Q18: map 的底层实现",[892,3693,3694],{},[1042,3695,3290],{},[1112,3697,3699],{"className":1114,"code":3698,"language":1116,"meta":11,"style":11},"type hmap struct {\n    count     int            \u002F\u002F 元素个数\n    B         uint8          \u002F\u002F bucket 数量 = 2^B\n    hash0     uint32         \u002F\u002F 哈希种子（随机化）\n    buckets   unsafe.Pointer \u002F\u002F bucket 数组\n    oldbuckets unsafe.Pointer \u002F\u002F 扩容时的旧 bucket\n}\n",[936,3700,3701,3712,3722,3732,3742,3756,3770],{"__ignoreMap":11},[1120,3702,3703,3705,3708,3710],{"class":1122,"line":1123},[1120,3704,1325],{"class":1137},[1120,3706,3707],{"class":1141}," hmap",[1120,3709,1331],{"class":1137},[1120,3711,1334],{"class":1133},[1120,3713,3714,3717,3719],{"class":1122,"line":1130},[1120,3715,3716],{"class":1133},"    count     ",[1120,3718,948],{"class":1137},[1120,3720,3721],{"class":1126},"            \u002F\u002F 元素个数\n",[1120,3723,3724,3727,3729],{"class":1122,"line":1156},[1120,3725,3726],{"class":1133},"    B         ",[1120,3728,974],{"class":1137},[1120,3730,3731],{"class":1126},"          \u002F\u002F bucket 数量 = 2^B\n",[1120,3733,3734,3737,3739],{"class":1122,"line":1177},[1120,3735,3736],{"class":1133},"    hash0     ",[1120,3738,980],{"class":1137},[1120,3740,3741],{"class":1126},"         \u002F\u002F 哈希种子（随机化）\n",[1120,3743,3744,3747,3749,3751,3753],{"class":1122,"line":1184},[1120,3745,3746],{"class":1133},"    buckets   ",[1120,3748,2164],{"class":1141},[1120,3750,2167],{"class":1133},[1120,3752,2170],{"class":1141},[1120,3754,3755],{"class":1126}," \u002F\u002F bucket 数组\n",[1120,3757,3758,3761,3763,3765,3767],{"class":1122,"line":1190},[1120,3759,3760],{"class":1133},"    oldbuckets ",[1120,3762,2164],{"class":1141},[1120,3764,2167],{"class":1133},[1120,3766,2170],{"class":1141},[1120,3768,3769],{"class":1126}," \u002F\u002F 扩容时的旧 bucket\n",[1120,3771,3772],{"class":1122,"line":1221},[1120,3773,1404],{"class":1133},[892,3775,3776],{},[1042,3777,3778],{},"bucket 结构：",[1667,3780,3781,3784,3787],{},[1293,3782,3783],{},"每个 bucket 存 8 个 key-value",[1293,3785,3786],{},"高 8 位哈希用于快速比较（tophash）",[1293,3788,3789],{},"溢出 bucket 用链表处理",[892,3791,3792],{},[1042,3793,3794],{},"扩容条件：",[1290,3796,3797,3800],{},[1293,3798,3799],{},"负载因子 > 6.5（翻倍扩容）",[1293,3801,3802],{},"overflow bucket 过多（等量扩容，整理碎片）",[895,3804],{},[903,3806,3808],{"id":3807},"q19-map-为什么是无序的","Q19: map 为什么是无序的",[1290,3810,3811,3817,3823],{},[1293,3812,3813,3816],{},[1042,3814,3815],{},"哈希分布","：key 按哈希值分布，不是按插入顺序",[1293,3818,3819,3822],{},[1042,3820,3821],{},"扩容迁移","：扩容时数据会重新分布到新 bucket",[1293,3824,3825,3828],{},[1042,3826,3827],{},"故意随机化","：Go 在遍历时故意加入随机起始位置",[895,3830],{},[903,3832,3834],{"id":3833},"q20-map-vs-syncmap-深度对比及增删改查实现细节","Q20: map vs sync.Map 深度对比及增删改查实现细节",[3836,3837,3839],"h4",{"id":3838},"_1-核心对比总结","1. 核心对比总结",[908,3841,3842,3854],{},[911,3843,3844],{},[914,3845,3846,3848,3851],{},[917,3847,1063],{"align":919},[917,3849,3850],{"align":919},"map (配合 RWMutex)",[917,3852,3853],{"align":919},"sync.Map",[925,3855,3856,3869,3882,3901,3914],{},[914,3857,3858,3863,3866],{},[930,3859,3860],{"align":919},[1042,3861,3862],{},"线程安全",[930,3864,3865],{"align":919},"不安全（需手动加锁）",[930,3867,3868],{"align":919},"并发安全",[914,3870,3871,3876,3879],{},[930,3872,3873],{"align":919},[1042,3874,3875],{},"锁颗粒度",[930,3877,3878],{"align":919},"整个 map（大锁），竞争激烈",[930,3880,3881],{"align":919},"读写分离，只有 dirty 部分加锁（细锁）",[914,3883,3884,3889,3895],{},[930,3885,3886],{"align":919},[1042,3887,3888],{},"性能场景",[930,3890,3891,3894],{"align":919},[1042,3892,3893],{},"写操作多","、通用场景",[930,3896,3897,3900],{"align":919},[1042,3898,3899],{},"读多写少","、Key 集合稳定、多核竞争",[914,3902,3903,3908,3911],{},[930,3904,3905],{"align":919},[1042,3906,3907],{},"内存占用",[930,3909,3910],{"align":919},"较低",[930,3912,3913],{"align":919},"较高（维护 read 和 dirty 两个 map）",[914,3915,3916,3921,3926],{},[930,3917,3918],{"align":919},[1042,3919,3920],{},"零值可用",[930,3922,3923,3925],{"align":919},[936,3924,1069],{}," 后可用，nil map 写会 panic",[930,3927,3928],{"align":919},"直接声明即可使用（开箱即用）",[3836,3930,3932],{"id":3931},"_2-map-的增删改查实现-hmap","2. map 的增删改查实现 (hmap)",[892,3934,3935,3936,3938,3939,3942],{},"Go 标准 ",[936,3937,1233],{}," 使用哈希表实现，采用 ",[1042,3940,3941],{},"链地址法"," 解决冲突：",[1667,3944,3945,3973,3982],{},[1293,3946,3947,3950,3951],{},[1042,3948,3949],{},"查 (Load)","：\n",[1290,3952,3953,3956,3959,3966],{},[1293,3954,3955],{},"计算 Key 的 Hash 值。",[1293,3957,3958],{},"取 Hash 低位定位于哪个 Bucket（桶）。",[1293,3960,3961,3962,3965],{},"遍历桶内的 8 个槽位，通过 ",[1042,3963,3964],{},"tophash","（Hash 高 8 位）快速过滤，再匹配 Key。",[1293,3967,3968,3969,3972],{},"若桶满且未找到，继续查找 ",[1042,3970,3971],{},"overflow bucket","（溢出桶）。",[1293,3974,3975,3978,3979,3685],{},[1042,3976,3977],{},"增\u002F改 (Store)","：定位到 Bucket 后，寻找空位或已存在的 Key。若负载因子 > 6.5 或溢出桶过多，触发 ",[1042,3980,3981],{},"渐进式扩容",[1293,3983,3984,3987],{},[1042,3985,3986],{},"删 (Delete)","：定位到槽位，将 Key\u002FValue 清理，并重置 tophash。",[3836,3989,3991],{"id":3990},"_3-syncmap-的增删改查实现-readdirty","3. sync.Map 的增删改查实现 (read\u002Fdirty)",[892,3993,3994,3996,3997,4000,4001,4004],{},[936,3995,3853],{}," 采用了 ",[1042,3998,3999],{},"读写分离"," 和 ",[1042,4002,4003],{},"内存换时间"," 的策略：",[1667,4006,4007,4036,4067,4093],{},[1293,4008,4009,1045,4012],{},[1042,4010,4011],{},"底层结构",[1667,4013,4014,4024,4030],{},[1293,4015,4016,4019,4020,4023],{},[936,4017,4018],{},"read","：原子访问（",[936,4021,4022],{},"atomic.Value","），包含只读数据，不加锁。",[1293,4025,4026,4029],{},[936,4027,4028],{},"dirty","：原生 map，包含全量数据，操作需加互斥锁。",[1293,4031,4032,4035],{},[936,4033,4034],{},"misses","：计数器，记录 read 未命中而查 dirty 的次数。",[1293,4037,4038,1045,4040],{},[1042,4039,3949],{},[1290,4041,4042,4048,4057],{},[1293,4043,4044,4045,4047],{},"先从 ",[936,4046,4018],{}," 原子读取，命中则返回（极其高效）。",[1293,4049,4050,4051,4054,4055,3685],{},"若未命中且 ",[936,4052,4053],{},"amended=true","（说明 dirty 有 read 没有的数据），加锁访问 ",[936,4056,4028],{},[1293,4058,4059,4062,4063,4066],{},[1042,4060,4061],{},"Miss 升级","：若 misses 达到 ",[936,4064,4065],{},"len(dirty)","，将 dirty 整体迁移给 read，清空 dirty，实现“冷数据变热”。",[1293,4068,4069,1045,4072],{},[1042,4070,4071],{},"增 (Store)",[1290,4073,4074,4088],{},[1293,4075,4076,4077,4079,4080,4083,4084,4087],{},"若 Key 在 ",[936,4078,4018],{}," 中且未被标记为 ",[936,4081,4082],{},"expunged","，尝试 ",[1042,4085,4086],{},"CAS"," 无锁更新。",[1293,4089,4090,4091,3685],{},"若 CAS 失败（不在 read 或已被删），加锁处理：双检查（Double Check），写入或更新 ",[936,4092,4028],{},[1293,4094,4095,1045,4097],{},[1042,4096,3986],{},[1290,4098,4099,4107],{},[1293,4100,4076,4101,4103,4104,4106],{},[936,4102,4018],{}," 中，直接将其 Value 标记为 ",[936,4105,2686],{},"（逻辑删除，无锁）。",[1293,4108,4109,4110,4112,4113,4115,4116,4118],{},"若不在 ",[936,4111,4018],{}," 且 ",[936,4114,4053],{},"，加锁物理删除 ",[936,4117,4028],{}," 中的 Key。",[3836,4120,4122],{"id":4121},"_4-为什么-syncmap-适合读多写少","4. 为什么 sync.Map 适合读多写少？",[892,4124,4125,4126,4128,4129,4132,4133,4135,4136,4139],{},"因为在读多写少的场景下，绝大多数操作都能在 ",[936,4127,4018],{}," map 中通过原子操作完成，完全避开了互斥锁，从而在大规模并发下性能远超 ",[936,4130,4131],{},"RWMutex + map","。而在写多的场景下，频繁的 ",[936,4134,4028],{}," 写入和 ",[936,4137,4138],{},"miss"," 迁移会导致性能陡降。",[895,4141],{},[903,4143,4145],{"id":4144},"q21-go中的map如何实现顺序读取","Q21: Go中的map如何实现顺序读取",[892,4147,4148],{},[1042,4149,4150],{},"map 本身无序，需要额外处理：",[1112,4152,4154],{"className":1114,"code":4153,"language":1116,"meta":11,"style":11},"\u002F\u002F 方法：收集 key 排序\nkeys := make([]string, 0, len(m))\nfor k := range m {\n    keys = append(keys, k)\n}\nsort.Strings(keys)\nfor _, k := range keys {\n    fmt.Println(k, m[k])\n}\n",[936,4155,4156,4161,4186,4202,4214,4218,4229,4243,4252],{"__ignoreMap":11},[1120,4157,4158],{"class":1122,"line":1123},[1120,4159,4160],{"class":1126},"\u002F\u002F 方法：收集 key 排序\n",[1120,4162,4163,4166,4168,4170,4172,4174,4176,4178,4180,4183],{"class":1122,"line":1130},[1120,4164,4165],{"class":1133},"keys ",[1120,4167,1138],{"class":1137},[1120,4169,1198],{"class":1141},[1120,4171,1166],{"class":1133},[1120,4173,1022],{"class":1137},[1120,4175,949],{"class":1133},[1120,4177,1208],{"class":1207},[1120,4179,949],{"class":1133},[1120,4181,4182],{"class":1141},"len",[1120,4184,4185],{"class":1133},"(m))\n",[1120,4187,4188,4191,4194,4196,4199],{"class":1122,"line":1156},[1120,4189,4190],{"class":1137},"for",[1120,4192,4193],{"class":1133}," k ",[1120,4195,1138],{"class":1137},[1120,4197,4198],{"class":1137}," range",[1120,4200,4201],{"class":1133}," m {\n",[1120,4203,4204,4207,4209,4211],{"class":1122,"line":1177},[1120,4205,4206],{"class":1133},"    keys ",[1120,4208,2094],{"class":1137},[1120,4210,3663],{"class":1141},[1120,4212,4213],{"class":1133},"(keys, k)\n",[1120,4215,4216],{"class":1122,"line":1184},[1120,4217,1404],{"class":1133},[1120,4219,4220,4223,4226],{"class":1122,"line":1190},[1120,4221,4222],{"class":1133},"sort.",[1120,4224,4225],{"class":1141},"Strings",[1120,4227,4228],{"class":1133},"(keys)\n",[1120,4230,4231,4233,4236,4238,4240],{"class":1122,"line":1221},[1120,4232,4190],{"class":1137},[1120,4234,4235],{"class":1133}," _, k ",[1120,4237,1138],{"class":1137},[1120,4239,4198],{"class":1137},[1120,4241,4242],{"class":1133}," keys {\n",[1120,4244,4245,4247,4249],{"class":1122,"line":1251},[1120,4246,2394],{"class":1133},[1120,4248,1901],{"class":1141},[1120,4250,4251],{"class":1133},"(k, m[k])\n",[1120,4253,4254],{"class":1122,"line":1504},[1120,4255,1404],{"class":1133},[895,4257],{},[903,4259,4261],{"id":4260},"q22-interface-的底层结构","Q22: interface 的底层结构",[892,4263,4264],{},[1042,4265,4266,4267,4270],{},"空接口 ",[936,4268,4269],{},"interface{}","（eface）：",[1112,4272,4274],{"className":1114,"code":4273,"language":1116,"meta":11,"style":11},"type eface struct {\n    _type *_type         \u002F\u002F 类型信息\n    data  unsafe.Pointer \u002F\u002F 数据指针\n}\n",[936,4275,4276,4286,4297,4310],{"__ignoreMap":11},[1120,4277,4278,4280,4282,4284],{"class":1122,"line":1123},[1120,4279,1325],{"class":1137},[1120,4281,2139],{"class":1141},[1120,4283,1331],{"class":1137},[1120,4285,1334],{"class":1133},[1120,4287,4288,4290,4292,4294],{"class":1122,"line":1130},[1120,4289,2148],{"class":1133},[1120,4291,1380],{"class":1137},[1120,4293,2153],{"class":1141},[1120,4295,4296],{"class":1126},"         \u002F\u002F 类型信息\n",[1120,4298,4299,4301,4303,4305,4307],{"class":1122,"line":1156},[1120,4300,2161],{"class":1133},[1120,4302,2164],{"class":1141},[1120,4304,2167],{"class":1133},[1120,4306,2170],{"class":1141},[1120,4308,4309],{"class":1126}," \u002F\u002F 数据指针\n",[1120,4311,4312],{"class":1122,"line":1177},[1120,4313,1404],{"class":1133},[892,4315,4316],{},[1042,4317,4318],{},"非空接口（iface）：",[1112,4320,4322],{"className":1114,"code":4321,"language":1116,"meta":11,"style":11},"type iface struct {\n    tab  *itab           \u002F\u002F 类型和方法表\n    data unsafe.Pointer  \u002F\u002F 数据指针\n}\n",[936,4323,4324,4335,4348,4362],{"__ignoreMap":11},[1120,4325,4326,4328,4331,4333],{"class":1122,"line":1123},[1120,4327,1325],{"class":1137},[1120,4329,4330],{"class":1141}," iface",[1120,4332,1331],{"class":1137},[1120,4334,1334],{"class":1133},[1120,4336,4337,4340,4342,4345],{"class":1122,"line":1130},[1120,4338,4339],{"class":1133},"    tab  ",[1120,4341,1380],{"class":1137},[1120,4343,4344],{"class":1141},"itab",[1120,4346,4347],{"class":1126},"           \u002F\u002F 类型和方法表\n",[1120,4349,4350,4353,4355,4357,4359],{"class":1122,"line":1156},[1120,4351,4352],{"class":1133},"    data ",[1120,4354,2164],{"class":1141},[1120,4356,2167],{"class":1133},[1120,4358,2170],{"class":1141},[1120,4360,4361],{"class":1126},"  \u002F\u002F 数据指针\n",[1120,4363,4364],{"class":1122,"line":1177},[1120,4365,1404],{"class":1133},[895,4367],{},[898,4369,4371],{"id":4370},"三并发编程","三、并发编程",[903,4373,4375],{"id":4374},"q23-协程线程进程的区别","Q23: 协程、线程、进程的区别",[908,4377,4378,4393],{},[911,4379,4380],{},[914,4381,4382,4384,4387,4390],{},[917,4383,1063],{"align":919},[917,4385,4386],{"align":919},"进程",[917,4388,4389],{"align":919},"线程",[917,4391,4392],{"align":919},"协程(Goroutine)",[925,4394,4395,4409,4423,4437,4450,4463],{},[914,4396,4397,4400,4403,4406],{},[930,4398,4399],{"align":919},"定义",[930,4401,4402],{"align":919},"资源分配单位",[930,4404,4405],{"align":919},"CPU 调度单位",[930,4407,4408],{"align":919},"用户态轻量级线程",[914,4410,4411,4414,4417,4420],{},[930,4412,4413],{"align":919},"内存",[930,4415,4416],{"align":919},"独立地址空间",[930,4418,4419],{"align":919},"共享进程内存",[930,4421,4422],{"align":919},"共享线程内存",[914,4424,4425,4428,4431,4434],{},[930,4426,4427],{"align":919},"创建开销",[930,4429,4430],{"align":919},"很大",[930,4432,4433],{"align":919},"较大(~1MB)",[930,4435,4436],{"align":919},"很小(~2KB)",[914,4438,4439,4442,4444,4447],{},[930,4440,4441],{"align":919},"切换开销",[930,4443,4430],{"align":919},[930,4445,4446],{"align":919},"较大(~1μs)",[930,4448,4449],{"align":919},"很小(~200ns)",[914,4451,4452,4455,4458,4460],{},[930,4453,4454],{"align":919},"调度",[930,4456,4457],{"align":919},"操作系统",[930,4459,4457],{"align":919},[930,4461,4462],{"align":919},"Go runtime(用户态)",[914,4464,4465,4468,4471,4474],{},[930,4466,4467],{"align":919},"数量级",[930,4469,4470],{"align":919},"数百",[930,4472,4473],{"align":919},"数千",[930,4475,4476],{"align":919},"数百万",[895,4478],{},[903,4480,4482],{"id":4481},"q24-goroutine和线程的区别","Q24: Goroutine和线程的区别",[908,4484,4485,4497],{},[911,4486,4487],{},[914,4488,4489,4491,4494],{},[917,4490,1063],{"align":919},[917,4492,4493],{"align":919},"Goroutine",[917,4495,4496],{"align":919},"OS Thread",[925,4498,4499,4509,4520,4531,4541,4552],{},[914,4500,4501,4503,4506],{},[930,4502,3907],{"align":919},[930,4504,4505],{"align":919},"初始 2KB，可动态增长",[930,4507,4508],{"align":919},"固定 1-8MB",[914,4510,4511,4514,4517],{},[930,4512,4513],{"align":919},"创建销毁",[930,4515,4516],{"align":919},"用户态，开销小",[930,4518,4519],{"align":919},"内核态，开销大",[914,4521,4522,4525,4528],{},[930,4523,4524],{"align":919},"切换成本",[930,4526,4527],{"align":919},"~200ns",[930,4529,4530],{"align":919},"~1-2μs",[914,4532,4533,4535,4538],{},[930,4534,4454],{"align":919},[930,4536,4537],{"align":919},"Go runtime（用户态）",[930,4539,4540],{"align":919},"操作系统（内核态）",[914,4542,4543,4546,4549],{},[930,4544,4545],{"align":919},"数量",[930,4547,4548],{"align":919},"可创建百万级",[930,4550,4551],{"align":919},"通常数千个",[914,4553,4554,4557,4560],{},[930,4555,4556],{"align":919},"栈",[930,4558,4559],{"align":919},"动态伸缩（2KB-1GB）",[930,4561,4562],{"align":919},"固定大小",[895,4564],{},[903,4566,4568],{"id":4567},"q25-goroutine和channel的作用分别是什么","Q25: Goroutine和Channel的作用分别是什么",[892,4570,4571],{},[1042,4572,4573],{},"Goroutine：",[1667,4575,4576,4579,4582],{},[1293,4577,4578],{},"轻量级并发执行单元",[1293,4580,4581],{},"由 Go runtime 调度",[1293,4583,4584],{},"初始内存仅 2KB",[892,4586,4587],{},[1042,4588,4589],{},"Channel：",[1667,4591,4592,4595,4598],{},[1293,4593,4594],{},"Goroutine 间的通信机制",[1293,4596,4597],{},"实现数据同步和传递",[1293,4599,4600],{},"保证并发安全",[892,4602,4603,4606],{},[1042,4604,4605],{},"协作关系：","\n> \"Don't communicate by sharing memory; share memory by communicating.\"",[895,4608],{},[903,4610,4612],{"id":4611},"q26-什么是channel为什么它可以做到线程安全","Q26: 什么是channel，为什么它可以做到线程安全",[892,4614,4615,4618],{},[1042,4616,4617],{},"Channel 是 Go 中的通信机制","，用于 goroutine 间传递数据。",[892,4620,4621],{},[1042,4622,3290],{},[1112,4624,4626],{"className":1114,"code":4625,"language":1116,"meta":11,"style":11},"type hchan struct {\n    qcount   uint           \u002F\u002F 当前元素数量\n    dataqsiz uint           \u002F\u002F 缓冲区大小\n    buf      unsafe.Pointer \u002F\u002F 环形队列指针\n    lock     mutex          \u002F\u002F 互斥锁（关键！）\n    sendq    waitq          \u002F\u002F 发送等待队列\n    recvq    waitq          \u002F\u002F 接收等待队列\n}\n",[936,4627,4628,4639,4649,4659,4673,4684,4695,4705],{"__ignoreMap":11},[1120,4629,4630,4632,4635,4637],{"class":1122,"line":1123},[1120,4631,1325],{"class":1137},[1120,4633,4634],{"class":1141}," hchan",[1120,4636,1331],{"class":1137},[1120,4638,1334],{"class":1133},[1120,4640,4641,4644,4646],{"class":1122,"line":1130},[1120,4642,4643],{"class":1133},"    qcount   ",[1120,4645,971],{"class":1137},[1120,4647,4648],{"class":1126},"           \u002F\u002F 当前元素数量\n",[1120,4650,4651,4654,4656],{"class":1122,"line":1156},[1120,4652,4653],{"class":1133},"    dataqsiz ",[1120,4655,971],{"class":1137},[1120,4657,4658],{"class":1126},"           \u002F\u002F 缓冲区大小\n",[1120,4660,4661,4664,4666,4668,4670],{"class":1122,"line":1177},[1120,4662,4663],{"class":1133},"    buf      ",[1120,4665,2164],{"class":1141},[1120,4667,2167],{"class":1133},[1120,4669,2170],{"class":1141},[1120,4671,4672],{"class":1126}," \u002F\u002F 环形队列指针\n",[1120,4674,4675,4678,4681],{"class":1122,"line":1184},[1120,4676,4677],{"class":1133},"    lock     ",[1120,4679,4680],{"class":1141},"mutex",[1120,4682,4683],{"class":1126},"          \u002F\u002F 互斥锁（关键！）\n",[1120,4685,4686,4689,4692],{"class":1122,"line":1190},[1120,4687,4688],{"class":1133},"    sendq    ",[1120,4690,4691],{"class":1141},"waitq",[1120,4693,4694],{"class":1126},"          \u002F\u002F 发送等待队列\n",[1120,4696,4697,4700,4702],{"class":1122,"line":1221},[1120,4698,4699],{"class":1133},"    recvq    ",[1120,4701,4691],{"class":1141},[1120,4703,4704],{"class":1126},"          \u002F\u002F 接收等待队列\n",[1120,4706,4707],{"class":1122,"line":1251},[1120,4708,1404],{"class":1133},[892,4710,4711],{},[1042,4712,4713],{},"线程安全原因：",[1290,4715,4716,4722,4728],{},[1293,4717,4718,4721],{},[1042,4719,4720],{},"内置互斥锁","：所有操作都在锁保护下进行",[1293,4723,4724,4727],{},[1042,4725,4726],{},"等待队列","：发送\u002F接收者会被安全地加入等待队列",[1293,4729,4730,4733],{},[1042,4731,4732],{},"原子操作","：关键状态使用原子操作更新",[895,4735],{},[903,4737,4739],{"id":4738},"q27-无缓冲chan的发送和接收是否同步","Q27: 无缓冲Chan的发送和接收是否同步",[892,4741,4742,4745],{},[1042,4743,4744],{},"是同步的。"," 无缓冲 Channel 发送和接收操作必须同时准备好才能完成。",[1112,4747,4749],{"className":1114,"code":4748,"language":1116,"meta":11,"style":11},"ch := make(chan int)  \u002F\u002F 无缓冲\n\ngo func() {\n    ch \u003C- 42  \u002F\u002F 阻塞直到有接收者\n}()\n\nval := \u003C-ch  \u002F\u002F 阻塞直到有发送者\n",[936,4750,4751,4770,4774,4782,4795,4800,4804],{"__ignoreMap":11},[1120,4752,4753,4755,4757,4759,4761,4763,4765,4767],{"class":1122,"line":1123},[1120,4754,1254],{"class":1133},[1120,4756,1138],{"class":1137},[1120,4758,1198],{"class":1141},[1120,4760,1145],{"class":1133},[1120,4762,1263],{"class":1137},[1120,4764,1266],{"class":1137},[1120,4766,2114],{"class":1133},[1120,4768,4769],{"class":1126},"\u002F\u002F 无缓冲\n",[1120,4771,4772],{"class":1122,"line":1130},[1120,4773,1181],{"emptyLinePlaceholder":1180},[1120,4775,4776,4778,4780],{"class":1122,"line":1156},[1120,4777,1116],{"class":1137},[1120,4779,1468],{"class":1137},[1120,4781,2729],{"class":1133},[1120,4783,4784,4787,4789,4792],{"class":1122,"line":1177},[1120,4785,4786],{"class":1133},"    ch ",[1120,4788,1615],{"class":1137},[1120,4790,4791],{"class":1207}," 42",[1120,4793,4794],{"class":1126},"  \u002F\u002F 阻塞直到有接收者\n",[1120,4796,4797],{"class":1122,"line":1184},[1120,4798,4799],{"class":1133},"}()\n",[1120,4801,4802],{"class":1122,"line":1190},[1120,4803,1181],{"emptyLinePlaceholder":1180},[1120,4805,4806,4809,4811,4813,4816],{"class":1122,"line":1221},[1120,4807,4808],{"class":1133},"val ",[1120,4810,1138],{"class":1137},[1120,4812,1597],{"class":1137},[1120,4814,4815],{"class":1133},"ch  ",[1120,4817,4818],{"class":1126},"\u002F\u002F 阻塞直到有发送者\n",[895,4820],{},[903,4822,4824],{"id":4823},"q28-channel是同步的还是异步的","Q28: Channel是同步的还是异步的",[892,4826,4827],{},[1042,4828,4829],{},"取决于是否有缓冲：",[908,4831,4832,4844],{},[911,4833,4834],{},[914,4835,4836,4838,4841],{},[917,4837,923],{"align":919},[917,4839,4840],{"align":919},"创建方式",[917,4842,4843],{"align":919},"同步性",[925,4845,4846,4859],{},[914,4847,4848,4851,4856],{},[930,4849,4850],{"align":919},"无缓冲",[930,4852,4853],{"align":919},[936,4854,4855],{},"make(chan T)",[930,4857,4858],{"align":919},"同步",[914,4860,4861,4864,4869],{},[930,4862,4863],{"align":919},"有缓冲",[930,4865,4866],{"align":919},[936,4867,4868],{},"make(chan T, n)",[930,4870,4871],{"align":919},"异步（缓冲区未满时）",[895,4873],{},[903,4875,4877],{"id":4876},"q29-channel-操作的各种情况","Q29: Channel 操作的各种情况",[908,4879,4880,4895],{},[911,4881,4882],{},[914,4883,4884,4886,4889,4892],{},[917,4885,3526],{"align":919},[917,4887,4888],{"align":919},"nil channel",[917,4890,4891],{"align":919},"已关闭 channel",[917,4893,4894],{"align":919},"正常 channel",[925,4896,4897,4912,4924],{},[914,4898,4899,4902,4905,4909],{},[930,4900,4901],{"align":919},"发送",[930,4903,4904],{"align":919},"永久阻塞",[930,4906,4907],{"align":919},[1042,4908,2651],{},[930,4910,4911],{"align":919},"阻塞或成功",[914,4913,4914,4917,4919,4922],{},[930,4915,4916],{"align":919},"接收",[930,4918,4904],{"align":919},[930,4920,4921],{"align":919},"返回零值，ok=false",[930,4923,4911],{"align":919},[914,4925,4926,4929,4933,4937],{},[930,4927,4928],{"align":919},"关闭",[930,4930,4931],{"align":919},[1042,4932,2651],{},[930,4934,4935],{"align":919},[1042,4936,2651],{},[930,4938,4939],{"align":919},"成功",[895,4941],{},[903,4943,4945],{"id":4944},"q30-golang并发机制以及csp并发模型","Q30: Golang并发机制以及CSP并发模型",[892,4947,4948],{},[1042,4949,4950],{},"CSP（Communicating Sequential Processes）模型核心思想：",[892,4952,4953],{},"> \"不要通过共享内存来通信，而要通过通信来共享内存\"",[892,4955,4956],{},[1042,4957,4958],{},"Go 的并发机制：",[1290,4960,4961,4966,4972],{},[1293,4962,4963,4965],{},[1042,4964,4493],{},"：轻量级线程，由 Go runtime 调度",[1293,4967,4968,4971],{},[1042,4969,4970],{},"Channel","：goroutine 间的通信管道",[1293,4973,4974,4977],{},[1042,4975,4976],{},"Select","：多路复用机制",[908,4979,4980,4990],{},[911,4981,4982],{},[914,4983,4984,4987],{},[917,4985,4986],{"align":919},"传统模型",[917,4988,4989],{"align":919},"CSP 模型",[925,4991,4992,5000],{},[914,4993,4994,4997],{},[930,4995,4996],{"align":919},"共享内存 + 锁",[930,4998,4999],{"align":919},"通过 Channel 通信",[914,5001,5002,5005],{},[930,5003,5004],{"align":919},"容易死锁",[930,5006,5007],{"align":919},"更安全的并发模式",[895,5009],{},[903,5011,5013],{"id":5012},"q31-golang中除了加mutex锁以外还有哪些方式安全读写共享变量","Q31: Golang中除了加Mutex锁以外还有哪些方式安全读写共享变量",[908,5015,5016,5028],{},[911,5017,5018],{},[914,5019,5020,5022,5025],{},[917,5021,3222],{"align":919},[917,5023,5024],{"align":919},"适用场景",[917,5026,5027],{"align":919},"说明",[925,5029,5030,5042,5054,5068],{},[914,5031,5032,5037,5039],{},[930,5033,5034],{"align":919},[936,5035,5036],{},"sync.RWMutex",[930,5038,3899],{"align":919},[930,5040,5041],{"align":919},"读锁共享，写锁排他",[914,5043,5044,5048,5051],{},[930,5045,5046],{"align":919},[936,5047,3853],{},[930,5049,5050],{"align":919},"并发 map",[930,5052,5053],{"align":919},"内置并发安全的 map",[914,5055,5056,5062,5065],{},[930,5057,5058,5061],{"align":919},[936,5059,5060],{},"atomic"," 包",[930,5063,5064],{"align":919},"简单类型",[930,5066,5067],{"align":919},"原子操作，无锁高性能",[914,5069,5070,5075,5078],{},[930,5071,5072],{"align":919},[936,5073,5074],{},"channel",[930,5076,5077],{"align":919},"数据传递",[930,5079,5080],{"align":919},"CSP 模型，通过通信共享内存",[895,5082],{},[903,5084,5086],{"id":5085},"q32-go中的锁有哪些","Q32: Go中的锁有哪些",[908,5088,5089,5101],{},[911,5090,5091],{},[914,5092,5093,5096,5098],{},[917,5094,5095],{"align":919},"锁类型",[917,5097,5027],{"align":919},[917,5099,5100],{"align":919},"使用场景",[925,5102,5103,5116,5127,5140,5153,5165],{},[914,5104,5105,5110,5113],{},[930,5106,5107],{"align":919},[936,5108,5109],{},"sync.Mutex",[930,5111,5112],{"align":919},"互斥锁",[930,5114,5115],{"align":919},"保护临界区",[914,5117,5118,5122,5125],{},[930,5119,5120],{"align":919},[936,5121,5036],{},[930,5123,5124],{"align":919},"读写锁",[930,5126,3899],{"align":919},[914,5128,5129,5134,5137],{},[930,5130,5131],{"align":919},[936,5132,5133],{},"sync.Once",[930,5135,5136],{"align":919},"单次执行",[930,5138,5139],{"align":919},"单例初始化",[914,5141,5142,5147,5150],{},[930,5143,5144],{"align":919},[936,5145,5146],{},"sync.Cond",[930,5148,5149],{"align":919},"条件变量",[930,5151,5152],{"align":919},"等待条件满足",[914,5154,5155,5159,5162],{},[930,5156,5157],{"align":919},[936,5158,3853],{},[930,5160,5161],{"align":919},"并发安全 map",[930,5163,5164],{"align":919},"并发 map 操作",[914,5166,5167,5171,5173],{},[930,5168,5169],{"align":919},[936,5170,5060],{},[930,5172,4732],{"align":919},[930,5174,5175],{"align":919},"简单类型原子操作",[895,5177],{},[903,5179,5181],{"id":5180},"q33-go中的锁如何实现","Q33: Go中的锁如何实现",[892,5183,5184],{},[1042,5185,5186],{},"sync.Mutex 实现原理：",[1112,5188,5190],{"className":1114,"code":5189,"language":1116,"meta":11,"style":11},"type Mutex struct {\n    state int32   \u002F\u002F 锁状态（locked、woken、starving、waiter count）\n    sema  uint32  \u002F\u002F 信号量\n}\n",[936,5191,5192,5203,5213,5223],{"__ignoreMap":11},[1120,5193,5194,5196,5199,5201],{"class":1122,"line":1123},[1120,5195,1325],{"class":1137},[1120,5197,5198],{"class":1141}," Mutex",[1120,5200,1331],{"class":1137},[1120,5202,1334],{"class":1133},[1120,5204,5205,5208,5210],{"class":1122,"line":1130},[1120,5206,5207],{"class":1133},"    state ",[1120,5209,958],{"class":1137},[1120,5211,5212],{"class":1126},"   \u002F\u002F 锁状态（locked、woken、starving、waiter count）\n",[1120,5214,5215,5218,5220],{"class":1122,"line":1156},[1120,5216,5217],{"class":1133},"    sema  ",[1120,5219,980],{"class":1137},[1120,5221,5222],{"class":1126},"  \u002F\u002F 信号量\n",[1120,5224,5225],{"class":1122,"line":1177},[1120,5226,1404],{"class":1133},[892,5228,5229],{},[1042,5230,5231],{},"两种模式：",[1290,5233,5234,5240],{},[1293,5235,5236,5239],{},[1042,5237,5238],{},"正常模式","：自旋尝试获取锁 → 失败后加入等待队列 → FIFO 唤醒",[1293,5241,5242,5245],{},[1042,5243,5244],{},"饥饿模式","：等待超过 1ms 切换 → 直接把锁交给等待者 → 防止尾部延迟",[895,5247],{},[903,5249,5251],{"id":5250},"q34-go中cas是怎么回事","Q34: Go中CAS是怎么回事",[892,5253,5254],{},[1042,5255,5256],{},"CAS（Compare And Swap）是原子操作：",[1112,5258,5260],{"className":1114,"code":5259,"language":1116,"meta":11,"style":11},"\u002F\u002F 如果 addr 的值等于 old，则替换为 new\nfunc CompareAndSwapInt64(addr *int64, old, new int64) bool\n",[936,5261,5262,5267],{"__ignoreMap":11},[1120,5263,5264],{"class":1122,"line":1123},[1120,5265,5266],{"class":1126},"\u002F\u002F 如果 addr 的值等于 old，则替换为 new\n",[1120,5268,5269,5271,5274,5276,5279,5282,5284,5287,5289,5291,5294,5296],{"class":1122,"line":1130},[1120,5270,1440],{"class":1137},[1120,5272,5273],{"class":1141}," CompareAndSwapInt64",[1120,5275,1145],{"class":1133},[1120,5277,5278],{"class":1515},"addr",[1120,5280,5281],{"class":1137}," *int64",[1120,5283,949],{"class":1133},[1120,5285,5286],{"class":1515},"old",[1120,5288,949],{"class":1133},[1120,5290,1066],{"class":1515},[1120,5292,5293],{"class":1137}," int64",[1120,5295,2519],{"class":1133},[1120,5297,1352],{"class":1137},[1112,5299,5301],{"className":1114,"code":5300,"language":1116,"meta":11,"style":11},"var counter int64\n\n\u002F\u002F CAS 自旋\nfor {\n    old := atomic.LoadInt64(&counter)\n    if atomic.CompareAndSwapInt64(&counter, old, old+1) {\n        break\n    }\n}\n",[936,5302,5303,5313,5317,5322,5328,5348,5372,5377,5382],{"__ignoreMap":11},[1120,5304,5305,5307,5310],{"class":1122,"line":1123},[1120,5306,2066],{"class":1137},[1120,5308,5309],{"class":1133}," counter ",[1120,5311,5312],{"class":1137},"int64\n",[1120,5314,5315],{"class":1122,"line":1130},[1120,5316,1181],{"emptyLinePlaceholder":1180},[1120,5318,5319],{"class":1122,"line":1156},[1120,5320,5321],{"class":1126},"\u002F\u002F CAS 自旋\n",[1120,5323,5324,5326],{"class":1122,"line":1177},[1120,5325,4190],{"class":1137},[1120,5327,1334],{"class":1133},[1120,5329,5330,5333,5335,5338,5341,5343,5345],{"class":1122,"line":1184},[1120,5331,5332],{"class":1133},"    old ",[1120,5334,1138],{"class":1137},[1120,5336,5337],{"class":1133}," atomic.",[1120,5339,5340],{"class":1141},"LoadInt64",[1120,5342,1145],{"class":1133},[1120,5344,2385],{"class":1137},[1120,5346,5347],{"class":1133},"counter)\n",[1120,5349,5350,5353,5355,5358,5360,5362,5365,5367,5370],{"class":1122,"line":1190},[1120,5351,5352],{"class":1137},"    if",[1120,5354,5337],{"class":1133},[1120,5356,5357],{"class":1141},"CompareAndSwapInt64",[1120,5359,1145],{"class":1133},[1120,5361,2385],{"class":1137},[1120,5363,5364],{"class":1133},"counter, old, old",[1120,5366,3236],{"class":1137},[1120,5368,5369],{"class":1207},"1",[1120,5371,1521],{"class":1133},[1120,5373,5374],{"class":1122,"line":1221},[1120,5375,5376],{"class":1137},"        break\n",[1120,5378,5379],{"class":1122,"line":1251},[1120,5380,5381],{"class":1133},"    }\n",[1120,5383,5384],{"class":1122,"line":1504},[1120,5385,1404],{"class":1133},[892,5387,5388,5390],{},[1042,5389,1665],{}," 无锁并发、硬件级别原子性、适用于简单类型",[895,5392],{},[903,5394,5396],{"id":5395},"q35-go中数据竞争问题怎么解决","Q35: Go中数据竞争问题怎么解决",[892,5398,5399],{},[1042,5400,5401],{},"检测工具：",[1112,5403,5407],{"className":5404,"code":5405,"language":5406,"meta":11,"style":11},"language-bash shiki shiki-themes github-light github-light github-dark","go run -race main.go    # 运行时检测\ngo test -race .\u002F...     # 测试时检测\n","bash",[936,5408,5409,5425],{"__ignoreMap":11},[1120,5410,5411,5413,5416,5419,5422],{"class":1122,"line":1123},[1120,5412,1116],{"class":1141},[1120,5414,5415],{"class":1866}," run",[1120,5417,5418],{"class":1207}," -race",[1120,5420,5421],{"class":1866}," main.go",[1120,5423,5424],{"class":1126},"    # 运行时检测\n",[1120,5426,5427,5429,5432,5434,5437],{"class":1122,"line":1130},[1120,5428,1116],{"class":1141},[1120,5430,5431],{"class":1866}," test",[1120,5433,5418],{"class":1207},[1120,5435,5436],{"class":1866}," .\u002F...",[1120,5438,5439],{"class":1126},"     # 测试时检测\n",[892,5441,5442,5445],{},[1042,5443,5444],{},"解决方案："," Mutex、RWMutex、Atomic、Channel、sync.Once",[895,5447],{},[903,5449,5451],{"id":5450},"q36-golang中常用的并发模型","Q36: Golang中常用的并发模型",[892,5453,5454],{},[1042,5455,5456],{},"1. Worker Pool（工作池）",[1112,5458,5460],{"className":1114,"code":5459,"language":1116,"meta":11,"style":11},"jobs := make(chan int, 100)\nfor w := 0; w \u003C 10; w++ {\n    go worker(jobs)  \u002F\u002F 固定 worker 数量\n}\n",[936,5461,5462,5483,5510,5524],{"__ignoreMap":11},[1120,5463,5464,5467,5469,5471,5473,5475,5477,5479,5481],{"class":1122,"line":1123},[1120,5465,5466],{"class":1133},"jobs ",[1120,5468,1138],{"class":1137},[1120,5470,1198],{"class":1141},[1120,5472,1145],{"class":1133},[1120,5474,1263],{"class":1137},[1120,5476,1266],{"class":1137},[1120,5478,949],{"class":1133},[1120,5480,2675],{"class":1207},[1120,5482,2591],{"class":1133},[1120,5484,5485,5487,5490,5492,5495,5498,5500,5503,5506,5508],{"class":1122,"line":1130},[1120,5486,4190],{"class":1137},[1120,5488,5489],{"class":1133}," w ",[1120,5491,1138],{"class":1137},[1120,5493,5494],{"class":1207}," 0",[1120,5496,5497],{"class":1133},"; w ",[1120,5499,3364],{"class":1137},[1120,5501,5502],{"class":1207}," 10",[1120,5504,5505],{"class":1133},"; w",[1120,5507,1474],{"class":1137},[1120,5509,1334],{"class":1133},[1120,5511,5512,5515,5518,5521],{"class":1122,"line":1156},[1120,5513,5514],{"class":1137},"    go",[1120,5516,5517],{"class":1141}," worker",[1120,5519,5520],{"class":1133},"(jobs)  ",[1120,5522,5523],{"class":1126},"\u002F\u002F 固定 worker 数量\n",[1120,5525,5526],{"class":1122,"line":1177},[1120,5527,1404],{"class":1133},[892,5529,5530],{},[1042,5531,5532],{},"2. Pipeline（管道）",[1112,5534,5536],{"className":1114,"code":5535,"language":1116,"meta":11,"style":11},"func gen() \u003C-chan int { ... }\nfunc sq(in \u003C-chan int) \u003C-chan int { ... }\n",[936,5537,5538,5561],{"__ignoreMap":11},[1120,5539,5540,5542,5545,5547,5550,5552,5555,5558],{"class":1122,"line":1123},[1120,5541,1440],{"class":1137},[1120,5543,5544],{"class":1141}," gen",[1120,5546,1446],{"class":1133},[1120,5548,5549],{"class":1137},"\u003C-chan",[1120,5551,1266],{"class":1137},[1120,5553,5554],{"class":1133}," { ",[1120,5556,5557],{"class":1137},"...",[1120,5559,5560],{"class":1133}," }\n",[1120,5562,5563,5565,5568,5570,5573,5576,5578,5580,5582,5584,5586,5588],{"class":1122,"line":1130},[1120,5564,1440],{"class":1137},[1120,5566,5567],{"class":1141}," sq",[1120,5569,1145],{"class":1133},[1120,5571,5572],{"class":1515},"in",[1120,5574,5575],{"class":1137}," \u003C-chan",[1120,5577,1266],{"class":1137},[1120,5579,2519],{"class":1133},[1120,5581,5549],{"class":1137},[1120,5583,1266],{"class":1137},[1120,5585,5554],{"class":1133},[1120,5587,5557],{"class":1137},[1120,5589,5560],{"class":1133},[892,5591,5592],{},[1042,5593,5594],{},"3. Fan-out\u002FFan-in",[1667,5596,5597,5600],{},[1293,5598,5599],{},"Fan-out：多个 goroutine 读取同一个 channel",[1293,5601,5602],{},"Fan-in：多个 channel 合并到一个",[892,5604,5605],{},[1042,5606,5607],{},"4. Semaphore（信号量）",[1112,5609,5611],{"className":1114,"code":5610,"language":1116,"meta":11,"style":11},"sem := make(chan struct{}, 10)  \u002F\u002F 最多 10 个并发\n",[936,5612,5613],{"__ignoreMap":11},[1120,5614,5615,5618,5620,5622,5624,5626,5628,5631,5633,5635],{"class":1122,"line":1123},[1120,5616,5617],{"class":1133},"sem ",[1120,5619,1138],{"class":1137},[1120,5621,1198],{"class":1141},[1120,5623,1145],{"class":1133},[1120,5625,1263],{"class":1137},[1120,5627,1331],{"class":1137},[1120,5629,5630],{"class":1133},"{}, ",[1120,5632,1213],{"class":1207},[1120,5634,2114],{"class":1133},[1120,5636,5637],{"class":1126},"\u002F\u002F 最多 10 个并发\n",[895,5639],{},[903,5641,5643],{"id":5642},"q37-怎么限制goroutine的数量","Q37: 怎么限制Goroutine的数量",[892,5645,5646],{},[1042,5647,5648],{},"方法一：带缓冲 Channel（信号量）",[1112,5650,5652],{"className":1114,"code":5651,"language":1116,"meta":11,"style":11},"sem := make(chan struct{}, 10)  \u002F\u002F 最多 10 个\n\nfor i := 0; i \u003C 100; i++ {\n    sem \u003C- struct{}{}  \u002F\u002F 获取\n    go func() {\n        defer func() { \u003C-sem }()  \u002F\u002F 释放\n        \u002F\u002F work...\n    }()\n}\n",[936,5653,5654,5677,5681,5705,5720,5728,5746,5751,5755],{"__ignoreMap":11},[1120,5655,5656,5658,5660,5662,5664,5666,5668,5670,5672,5674],{"class":1122,"line":1123},[1120,5657,5617],{"class":1133},[1120,5659,1138],{"class":1137},[1120,5661,1198],{"class":1141},[1120,5663,1145],{"class":1133},[1120,5665,1263],{"class":1137},[1120,5667,1331],{"class":1137},[1120,5669,5630],{"class":1133},[1120,5671,1213],{"class":1207},[1120,5673,2114],{"class":1133},[1120,5675,5676],{"class":1126},"\u002F\u002F 最多 10 个\n",[1120,5678,5679],{"class":1122,"line":1130},[1120,5680,1181],{"emptyLinePlaceholder":1180},[1120,5682,5683,5685,5687,5689,5691,5694,5696,5698,5701,5703],{"class":1122,"line":1156},[1120,5684,4190],{"class":1137},[1120,5686,2085],{"class":1133},[1120,5688,1138],{"class":1137},[1120,5690,5494],{"class":1207},[1120,5692,5693],{"class":1133},"; i ",[1120,5695,3364],{"class":1137},[1120,5697,3650],{"class":1207},[1120,5699,5700],{"class":1133},"; i",[1120,5702,1474],{"class":1137},[1120,5704,1334],{"class":1133},[1120,5706,5707,5710,5712,5714,5717],{"class":1122,"line":1177},[1120,5708,5709],{"class":1133},"    sem ",[1120,5711,1615],{"class":1137},[1120,5713,1331],{"class":1137},[1120,5715,5716],{"class":1133},"{}{}  ",[1120,5718,5719],{"class":1126},"\u002F\u002F 获取\n",[1120,5721,5722,5724,5726],{"class":1122,"line":1184},[1120,5723,5514],{"class":1137},[1120,5725,1468],{"class":1137},[1120,5727,2729],{"class":1133},[1120,5729,5730,5733,5735,5738,5740,5743],{"class":1122,"line":1190},[1120,5731,5732],{"class":1137},"        defer",[1120,5734,1468],{"class":1137},[1120,5736,5737],{"class":1133},"() { ",[1120,5739,1615],{"class":1137},[1120,5741,5742],{"class":1133},"sem }()  ",[1120,5744,5745],{"class":1126},"\u002F\u002F 释放\n",[1120,5747,5748],{"class":1122,"line":1221},[1120,5749,5750],{"class":1126},"        \u002F\u002F work...\n",[1120,5752,5753],{"class":1122,"line":1251},[1120,5754,2806],{"class":1133},[1120,5756,5757],{"class":1122,"line":1504},[1120,5758,1404],{"class":1133},[892,5760,5761,5764],{},[1042,5762,5763],{},"方法二：Worker Pool","（见上题）",[892,5766,5767],{},[1042,5768,5769],{},"方法三：第三方库",[1667,5771,5772,5777],{},[1293,5773,5774],{},[936,5775,5776],{},"golang.org\u002Fx\u002Fsync\u002Fsemaphore",[1293,5778,5779,5782],{},[936,5780,5781],{},"ants","（高性能协程池）",[895,5784],{},[903,5786,5788],{"id":5787},"q38-怎么查看goroutine的数量","Q38: 怎么查看Goroutine的数量",[1112,5790,5792],{"className":1114,"code":5791,"language":1116,"meta":11,"style":11},"\u002F\u002F 方法一：runtime\nfmt.Println(runtime.NumGoroutine())\n\n\u002F\u002F 方法二：pprof\nimport _ \"net\u002Fhttp\u002Fpprof\"\ngo http.ListenAndServe(\":6060\", nil)\n\u002F\u002F 访问 http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fgoroutine\n",[936,5793,5794,5799,5814,5818,5823,5839,5860],{"__ignoreMap":11},[1120,5795,5796],{"class":1122,"line":1123},[1120,5797,5798],{"class":1126},"\u002F\u002F 方法一：runtime\n",[1120,5800,5801,5803,5805,5808,5811],{"class":1122,"line":1130},[1120,5802,1898],{"class":1133},[1120,5804,1901],{"class":1141},[1120,5806,5807],{"class":1133},"(runtime.",[1120,5809,5810],{"class":1141},"NumGoroutine",[1120,5812,5813],{"class":1133},"())\n",[1120,5815,5816],{"class":1122,"line":1156},[1120,5817,1181],{"emptyLinePlaceholder":1180},[1120,5819,5820],{"class":1122,"line":1177},[1120,5821,5822],{"class":1126},"\u002F\u002F 方法二：pprof\n",[1120,5824,5825,5828,5831,5833,5836],{"class":1122,"line":1184},[1120,5826,5827],{"class":1137},"import",[1120,5829,5830],{"class":1133}," _ ",[1120,5832,2301],{"class":1866},[1120,5834,5835],{"class":1141},"net\u002Fhttp\u002Fpprof",[1120,5837,5838],{"class":1866},"\"\n",[1120,5840,5841,5843,5846,5849,5851,5854,5856,5858],{"class":1122,"line":1190},[1120,5842,1116],{"class":1137},[1120,5844,5845],{"class":1133}," http.",[1120,5847,5848],{"class":1141},"ListenAndServe",[1120,5850,1145],{"class":1133},[1120,5852,5853],{"class":1866},"\":6060\"",[1120,5855,949],{"class":1133},[1120,5857,2686],{"class":1207},[1120,5859,2591],{"class":1133},[1120,5861,5862],{"class":1122,"line":1221},[1120,5863,5864],{"class":1126},"\u002F\u002F 访问 http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fgoroutine\n",[895,5866],{},[903,5868,5870],{"id":5869},"q39-go主协程如何等其余协程完再操作","Q39: Go主协程如何等其余协程完再操作",[892,5872,5873],{},[1042,5874,5875],{},"方法一：sync.WaitGroup（推荐）",[1112,5877,5879],{"className":1114,"code":5878,"language":1116,"meta":11,"style":11},"var wg sync.WaitGroup\nfor i := 0; i \u003C 10; i++ {\n    wg.Add(1)\n    go func() {\n        defer wg.Done()\n        \u002F\u002F work...\n    }()\n}\nwg.Wait()  \u002F\u002F 等待所有完成\n",[936,5880,5881,5896,5918,5932,5940,5952,5956,5960,5964],{"__ignoreMap":11},[1120,5882,5883,5885,5888,5891,5893],{"class":1122,"line":1123},[1120,5884,2066],{"class":1137},[1120,5886,5887],{"class":1133}," wg ",[1120,5889,5890],{"class":1141},"sync",[1120,5892,2167],{"class":1133},[1120,5894,5895],{"class":1141},"WaitGroup\n",[1120,5897,5898,5900,5902,5904,5906,5908,5910,5912,5914,5916],{"class":1122,"line":1130},[1120,5899,4190],{"class":1137},[1120,5901,2085],{"class":1133},[1120,5903,1138],{"class":1137},[1120,5905,5494],{"class":1207},[1120,5907,5693],{"class":1133},[1120,5909,3364],{"class":1137},[1120,5911,5502],{"class":1207},[1120,5913,5700],{"class":1133},[1120,5915,1474],{"class":1137},[1120,5917,1334],{"class":1133},[1120,5919,5920,5923,5926,5928,5930],{"class":1122,"line":1156},[1120,5921,5922],{"class":1133},"    wg.",[1120,5924,5925],{"class":1141},"Add",[1120,5927,1145],{"class":1133},[1120,5929,5369],{"class":1207},[1120,5931,2591],{"class":1133},[1120,5933,5934,5936,5938],{"class":1122,"line":1177},[1120,5935,5514],{"class":1137},[1120,5937,1468],{"class":1137},[1120,5939,2729],{"class":1133},[1120,5941,5942,5944,5947,5950],{"class":1122,"line":1184},[1120,5943,5732],{"class":1137},[1120,5945,5946],{"class":1133}," wg.",[1120,5948,5949],{"class":1141},"Done",[1120,5951,2796],{"class":1133},[1120,5953,5954],{"class":1122,"line":1190},[1120,5955,5750],{"class":1126},[1120,5957,5958],{"class":1122,"line":1221},[1120,5959,2806],{"class":1133},[1120,5961,5962],{"class":1122,"line":1251},[1120,5963,1404],{"class":1133},[1120,5965,5966,5969,5972,5975],{"class":1122,"line":1504},[1120,5967,5968],{"class":1133},"wg.",[1120,5970,5971],{"class":1141},"Wait",[1120,5973,5974],{"class":1133},"()  ",[1120,5976,5977],{"class":1126},"\u002F\u002F 等待所有完成\n",[892,5979,5980],{},[1042,5981,5982],{},"方法二：Channel",[892,5984,5985],{},[1042,5986,5987],{},"方法三：errgroup",[1112,5989,5991],{"className":1114,"code":5990,"language":1116,"meta":11,"style":11},"g, ctx := errgroup.WithContext(ctx)\ng.Go(func() error { ... })\nerr := g.Wait()\n",[936,5992,5993,6009,6032],{"__ignoreMap":11},[1120,5994,5995,5998,6000,6003,6006],{"class":1122,"line":1123},[1120,5996,5997],{"class":1133},"g, ctx ",[1120,5999,1138],{"class":1137},[1120,6001,6002],{"class":1133}," errgroup.",[1120,6004,6005],{"class":1141},"WithContext",[1120,6007,6008],{"class":1133},"(ctx)\n",[1120,6010,6011,6014,6017,6019,6021,6023,6025,6027,6029],{"class":1122,"line":1130},[1120,6012,6013],{"class":1133},"g.",[1120,6015,6016],{"class":1141},"Go",[1120,6018,1145],{"class":1133},[1120,6020,1440],{"class":1137},[1120,6022,1446],{"class":1133},[1120,6024,2857],{"class":1137},[1120,6026,5554],{"class":1133},[1120,6028,5557],{"class":1137},[1120,6030,6031],{"class":1133}," })\n",[1120,6033,6034,6036,6038,6041,6043],{"class":1122,"line":1156},[1120,6035,2605],{"class":1133},[1120,6037,1138],{"class":1137},[1120,6039,6040],{"class":1133}," g.",[1120,6042,5971],{"class":1141},[1120,6044,2796],{"class":1133},[895,6046],{},[903,6048,6050],{"id":6049},"q40-context-是什么它的应用场景有哪些","Q40: Context 是什么？它的应用场景有哪些？",[892,6052,6053,6056,6059,6060,6063,6064,3685],{},[1042,6054,6055],{},"Context 是什么：",[936,6057,6058],{},"Context"," 是 Go 语言标准库中的一个接口，主要用于在 API 边界之间以及 goroutine 之间传递",[1042,6061,6062],{},"截止日期（Deadlines）","、",[1042,6065,6066,6067,6070],{},"取消信号（Cancellation signals）",[1042,6068,6069],{},"以及","请求范围的值（Request-scoped values）",[892,6072,6073],{},[1042,6074,6075],{},"核心原理：",[1667,6077,6078,6091,6097],{},[1293,6079,6080,6083,6084,6087,6088,3685],{},[1042,6081,6082],{},"树状结构","：Context 形成一个树状继承体系。根节点通常是 ",[936,6085,6086],{},"context.Background()"," 或 ",[936,6089,6090],{},"context.TODO()",[1293,6092,6093,6096],{},[1042,6094,6095],{},"取消信号传播","：当父 Context 被取消时，所有由它衍生出来的子 Context 也会被取消。",[1293,6098,6099,6101],{},[1042,6100,3862],{},"：Context 是并发安全的，可以被传递给多个 goroutine。",[892,6103,6104],{},[1042,6105,6106],{},"Go 标准库提供的四种衍生的 Context：",[908,6108,6109,6119],{},[911,6110,6111],{},[914,6112,6113,6115,6117],{},[917,6114,2418],{"align":919},[917,6116,2421],{"align":919},[917,6118,2424],{"align":919},[925,6120,6121,6134,6147,6160],{},[914,6122,6123,6128,6131],{},[930,6124,6125],{"align":919},[936,6126,6127],{},"WithCancel",[930,6129,6130],{"align":919},"返回一个可手动取消的 Context",[930,6132,6133],{"align":919},"任务完成后手动停止协程",[914,6135,6136,6141,6144],{},[930,6137,6138],{"align":919},[936,6139,6140],{},"WithDeadline",[930,6142,6143],{"align":919},"在指定的时间点自动取消",[930,6145,6146],{"align":919},"限时任务、截止时间",[914,6148,6149,6154,6157],{},[930,6150,6151],{"align":919},[936,6152,6153],{},"WithTimeout",[930,6155,6156],{"align":919},"在指定的持续时间后自动取消",[930,6158,6159],{"align":919},"RPC 调用超时、数据库查询超时",[914,6161,6162,6167,6170],{},[930,6163,6164],{"align":919},[936,6165,6166],{},"WithValue",[930,6168,6169],{"align":919},"携带请求范围的键值对",[930,6171,6172],{"align":919},"传递 RequestID、TraceID、用户信息",[892,6174,6175],{},[1042,6176,6177],{},"应用场景：",[1290,6179,6180,6279,6373,6445],{},[1293,6181,6182,6185,6186],{},[1042,6183,6184],{},"超时控制（最常用）","：\n在做网络请求或数据库查询时，防止调用方因为下游响应慢而导致资源一直被占用。",[1112,6187,6189],{"className":1114,"code":6188,"language":1116,"meta":11,"style":11},"ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\ndefer cancel()\n\nreq, _ := http.NewRequestWithContext(ctx, \"GET\", \"https:\u002F\u002Fapi.example.com\", nil)\nresp, err := http.DefaultClient.Do(req)\n",[936,6190,6191,6220,6230,6234,6263],{"__ignoreMap":11},[1120,6192,6193,6196,6198,6201,6203,6206,6209,6212,6215,6217],{"class":1122,"line":1123},[1120,6194,6195],{"class":1133},"ctx, cancel ",[1120,6197,1138],{"class":1137},[1120,6199,6200],{"class":1133}," context.",[1120,6202,6153],{"class":1141},[1120,6204,6205],{"class":1133},"(context.",[1120,6207,6208],{"class":1141},"Background",[1120,6210,6211],{"class":1133},"(), ",[1120,6213,6214],{"class":1207},"2",[1120,6216,1380],{"class":1137},[1120,6218,6219],{"class":1133},"time.Second)\n",[1120,6221,6222,6225,6228],{"class":1122,"line":1130},[1120,6223,6224],{"class":1137},"defer",[1120,6226,6227],{"class":1141}," cancel",[1120,6229,2796],{"class":1133},[1120,6231,6232],{"class":1122,"line":1156},[1120,6233,1181],{"emptyLinePlaceholder":1180},[1120,6235,6236,6239,6241,6243,6246,6249,6252,6254,6257,6259,6261],{"class":1122,"line":1177},[1120,6237,6238],{"class":1133},"req, _ ",[1120,6240,1138],{"class":1137},[1120,6242,5845],{"class":1133},[1120,6244,6245],{"class":1141},"NewRequestWithContext",[1120,6247,6248],{"class":1133},"(ctx, ",[1120,6250,6251],{"class":1866},"\"GET\"",[1120,6253,949],{"class":1133},[1120,6255,6256],{"class":1866},"\"https:\u002F\u002Fapi.example.com\"",[1120,6258,949],{"class":1133},[1120,6260,2686],{"class":1207},[1120,6262,2591],{"class":1133},[1120,6264,6265,6268,6270,6273,6276],{"class":1122,"line":1184},[1120,6266,6267],{"class":1133},"resp, err ",[1120,6269,1138],{"class":1137},[1120,6271,6272],{"class":1133}," http.DefaultClient.",[1120,6274,6275],{"class":1141},"Do",[1120,6277,6278],{"class":1133},"(req)\n",[1293,6280,6281,6284,6285],{},[1042,6282,6283],{},"取消信号的级联传递","：\n当一个主任务被取消或失败时，与之相关的所有子任务（在不同的 goroutine 中）都应该立即停止。",[1112,6286,6288],{"className":1114,"code":6287,"language":1116,"meta":11,"style":11},"func main() {\n    ctx, cancel := context.WithCancel(context.Background())\n    go worker(ctx, \"worker1\")\n    go worker(ctx, \"worker2\")\n    time.Sleep(1 * time.Second)\n    cancel() \u002F\u002F 两个 worker 都会收到信号并退出\n}\n",[936,6289,6290,6298,6315,6328,6341,6359,6369],{"__ignoreMap":11},[1120,6291,6292,6294,6296],{"class":1122,"line":1123},[1120,6293,1440],{"class":1137},[1120,6295,2933],{"class":1141},[1120,6297,2729],{"class":1133},[1120,6299,6300,6303,6305,6307,6309,6311,6313],{"class":1122,"line":1130},[1120,6301,6302],{"class":1133},"    ctx, cancel ",[1120,6304,1138],{"class":1137},[1120,6306,6200],{"class":1133},[1120,6308,6127],{"class":1141},[1120,6310,6205],{"class":1133},[1120,6312,6208],{"class":1141},[1120,6314,5813],{"class":1133},[1120,6316,6317,6319,6321,6323,6326],{"class":1122,"line":1156},[1120,6318,5514],{"class":1137},[1120,6320,5517],{"class":1141},[1120,6322,6248],{"class":1133},[1120,6324,6325],{"class":1866},"\"worker1\"",[1120,6327,2591],{"class":1133},[1120,6329,6330,6332,6334,6336,6339],{"class":1122,"line":1177},[1120,6331,5514],{"class":1137},[1120,6333,5517],{"class":1141},[1120,6335,6248],{"class":1133},[1120,6337,6338],{"class":1866},"\"worker2\"",[1120,6340,2591],{"class":1133},[1120,6342,6343,6346,6349,6351,6353,6356],{"class":1122,"line":1184},[1120,6344,6345],{"class":1133},"    time.",[1120,6347,6348],{"class":1141},"Sleep",[1120,6350,1145],{"class":1133},[1120,6352,5369],{"class":1207},[1120,6354,6355],{"class":1137}," *",[1120,6357,6358],{"class":1133}," time.Second)\n",[1120,6360,6361,6364,6366],{"class":1122,"line":1190},[1120,6362,6363],{"class":1141},"    cancel",[1120,6365,1446],{"class":1133},[1120,6367,6368],{"class":1126},"\u002F\u002F 两个 worker 都会收到信号并退出\n",[1120,6370,6371],{"class":1122,"line":1221},[1120,6372,1404],{"class":1133},[1293,6374,6375,6378,6379],{},[1042,6376,6377],{},"跨 API 边界传递数据","：\n在 Web 框架（如 Gin）的中间件中，常用来传递 TraceID、用户登录信息等。",[1112,6380,6382],{"className":1114,"code":6381,"language":1116,"meta":11,"style":11},"\u002F\u002F 传递数据\nctx := context.WithValue(context.Background(), \"TraceID\", \"abc-123\")\n\u002F\u002F 获取数据\ntraceID := ctx.Value(\"TraceID\").(string)\n",[936,6383,6384,6389,6416,6421],{"__ignoreMap":11},[1120,6385,6386],{"class":1122,"line":1123},[1120,6387,6388],{"class":1126},"\u002F\u002F 传递数据\n",[1120,6390,6391,6394,6396,6398,6400,6402,6404,6406,6409,6411,6414],{"class":1122,"line":1130},[1120,6392,6393],{"class":1133},"ctx ",[1120,6395,1138],{"class":1137},[1120,6397,6200],{"class":1133},[1120,6399,6166],{"class":1141},[1120,6401,6205],{"class":1133},[1120,6403,6208],{"class":1141},[1120,6405,6211],{"class":1133},[1120,6407,6408],{"class":1866},"\"TraceID\"",[1120,6410,949],{"class":1133},[1120,6412,6413],{"class":1866},"\"abc-123\"",[1120,6415,2591],{"class":1133},[1120,6417,6418],{"class":1122,"line":1156},[1120,6419,6420],{"class":1126},"\u002F\u002F 获取数据\n",[1120,6422,6423,6426,6428,6431,6434,6436,6438,6441,6443],{"class":1122,"line":1177},[1120,6424,6425],{"class":1133},"traceID ",[1120,6427,1138],{"class":1137},[1120,6429,6430],{"class":1133}," ctx.",[1120,6432,6433],{"class":1141},"Value",[1120,6435,1145],{"class":1133},[1120,6437,6408],{"class":1866},[1120,6439,6440],{"class":1133},").(",[1120,6442,1022],{"class":1137},[1120,6444,2591],{"class":1133},[1293,6446,6447,6450,6451,6454],{},[1042,6448,6449],{},"防止 Goroutine 泄漏","：\n通过 Context 的 ",[936,6452,6453],{},"Done()"," 通道，确保 Goroutine 在任务不再需要时能及时退出。",[892,6456,6457],{},[1042,6458,6459],{},"使用原则：",[1667,6461,6462,6469,6477],{},[1293,6463,6464,6465,6468],{},"不要将 Context 放入结构体中，而是显式作为函数的第一个参数传递（通常命名为 ",[936,6466,6467],{},"ctx","）。",[1293,6470,6471,6472,6474,6475,3685],{},"不要传递 ",[936,6473,2686],{}," 的 Context，如果不确定用什么，使用 ",[936,6476,6090],{},[1293,6478,6479],{},"Context 仅用于传递请求范围的数据，不应用于传递函数的可选参数。",[895,6481],{},[903,6483,6485],{"id":6484},"q41-如何在goroutine执行一半就退出协程","Q41: 如何在goroutine执行一半就退出协程",[892,6487,6488],{},[1042,6489,6490],{},"方法一：context 取消（推荐）",[1112,6492,6494],{"className":1114,"code":6493,"language":1116,"meta":11,"style":11},"ctx, cancel := context.WithCancel(context.Background())\ngo func(ctx context.Context) {\n    for {\n        select {\n        case \u003C-ctx.Done():\n            return  \u002F\u002F 退出\n        default:\n            \u002F\u002F 工作...\n        }\n    }\n}(ctx)\ncancel()  \u002F\u002F 发送取消信号\n",[936,6495,6496,6512,6531,6538,6545,6560,6568,6575,6580,6584,6588,6593],{"__ignoreMap":11},[1120,6497,6498,6500,6502,6504,6506,6508,6510],{"class":1122,"line":1123},[1120,6499,6195],{"class":1133},[1120,6501,1138],{"class":1137},[1120,6503,6200],{"class":1133},[1120,6505,6127],{"class":1141},[1120,6507,6205],{"class":1133},[1120,6509,6208],{"class":1141},[1120,6511,5813],{"class":1133},[1120,6513,6514,6516,6518,6520,6522,6525,6527,6529],{"class":1122,"line":1130},[1120,6515,1116],{"class":1137},[1120,6517,1468],{"class":1137},[1120,6519,1145],{"class":1133},[1120,6521,6467],{"class":1515},[1120,6523,6524],{"class":1141}," context",[1120,6526,2167],{"class":1133},[1120,6528,6058],{"class":1141},[1120,6530,1521],{"class":1133},[1120,6532,6533,6536],{"class":1122,"line":1156},[1120,6534,6535],{"class":1137},"    for",[1120,6537,1334],{"class":1133},[1120,6539,6540,6543],{"class":1122,"line":1177},[1120,6541,6542],{"class":1137},"        select",[1120,6544,1334],{"class":1133},[1120,6546,6547,6550,6552,6555,6557],{"class":1122,"line":1184},[1120,6548,6549],{"class":1137},"        case",[1120,6551,1597],{"class":1137},[1120,6553,6554],{"class":1133},"ctx.",[1120,6556,5949],{"class":1141},[1120,6558,6559],{"class":1133},"():\n",[1120,6561,6562,6565],{"class":1122,"line":1190},[1120,6563,6564],{"class":1137},"            return",[1120,6566,6567],{"class":1126},"  \u002F\u002F 退出\n",[1120,6569,6570,6573],{"class":1122,"line":1221},[1120,6571,6572],{"class":1137},"        default",[1120,6574,1651],{"class":1133},[1120,6576,6577],{"class":1122,"line":1251},[1120,6578,6579],{"class":1126},"            \u002F\u002F 工作...\n",[1120,6581,6582],{"class":1122,"line":1504},[1120,6583,2801],{"class":1133},[1120,6585,6586],{"class":1122,"line":1524},[1120,6587,5381],{"class":1133},[1120,6589,6590],{"class":1122,"line":1537},[1120,6591,6592],{"class":1133},"}(ctx)\n",[1120,6594,6595,6598,6600],{"class":1122,"line":1548},[1120,6596,6597],{"class":1141},"cancel",[1120,6599,5974],{"class":1133},[1120,6601,6602],{"class":1126},"\u002F\u002F 发送取消信号\n",[892,6604,6605],{},[1042,6606,6607],{},"方法二：Channel 信号",[892,6609,6610],{},[1042,6611,6612],{},"方法三：runtime.Goexit()",[1112,6614,6616],{"className":1114,"code":6615,"language":1116,"meta":11,"style":11},"runtime.Goexit()  \u002F\u002F 立即终止当前 goroutine\n",[936,6617,6618],{"__ignoreMap":11},[1120,6619,6620,6623,6626,6628],{"class":1122,"line":1123},[1120,6621,6622],{"class":1133},"runtime.",[1120,6624,6625],{"class":1141},"Goexit",[1120,6627,5974],{"class":1133},[1120,6629,6630],{"class":1126},"\u002F\u002F 立即终止当前 goroutine\n",[895,6632],{},[903,6634,6636],{"id":6635},"q42-goroutine发生了泄漏如何检测","Q42: Goroutine发生了泄漏如何检测",[892,6638,6639],{},[1042,6640,6641],{},"常见泄漏原因：",[1667,6643,6644,6647,6650],{},[1293,6645,6646],{},"阻塞在 channel 上无法退出",[1293,6648,6649],{},"无限循环没有退出条件",[1293,6651,6652],{},"忘记关闭 channel",[892,6654,6655],{},[1042,6656,6657],{},"检测方法：",[1112,6659,6661],{"className":1114,"code":6660,"language":1116,"meta":11,"style":11},"\u002F\u002F 1. runtime\nfmt.Println(runtime.NumGoroutine())\n\n\u002F\u002F 2. pprof\ngo tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fgoroutine\n\n\u002F\u002F 3. goleak（测试用）\nfunc TestNoLeak(t *testing.T) {\n    defer goleak.VerifyNone(t)\n    \u002F\u002F test code\n}\n",[936,6662,6663,6668,6680,6684,6689,6699,6703,6708,6731,6744,6749],{"__ignoreMap":11},[1120,6664,6665],{"class":1122,"line":1123},[1120,6666,6667],{"class":1126},"\u002F\u002F 1. runtime\n",[1120,6669,6670,6672,6674,6676,6678],{"class":1122,"line":1130},[1120,6671,1898],{"class":1133},[1120,6673,1901],{"class":1141},[1120,6675,5807],{"class":1133},[1120,6677,5810],{"class":1141},[1120,6679,5813],{"class":1133},[1120,6681,6682],{"class":1122,"line":1156},[1120,6683,1181],{"emptyLinePlaceholder":1180},[1120,6685,6686],{"class":1122,"line":1177},[1120,6687,6688],{"class":1126},"\u002F\u002F 2. pprof\n",[1120,6690,6691,6693,6696],{"class":1122,"line":1184},[1120,6692,1116],{"class":1137},[1120,6694,6695],{"class":1133}," tool pprof http:",[1120,6697,6698],{"class":1126},"\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fgoroutine\n",[1120,6700,6701],{"class":1122,"line":1190},[1120,6702,1181],{"emptyLinePlaceholder":1180},[1120,6704,6705],{"class":1122,"line":1221},[1120,6706,6707],{"class":1126},"\u002F\u002F 3. goleak（测试用）\n",[1120,6709,6710,6712,6715,6717,6720,6722,6725,6727,6729],{"class":1122,"line":1251},[1120,6711,1440],{"class":1137},[1120,6713,6714],{"class":1141}," TestNoLeak",[1120,6716,1145],{"class":1133},[1120,6718,6719],{"class":1515},"t",[1120,6721,6355],{"class":1137},[1120,6723,6724],{"class":1141},"testing",[1120,6726,2167],{"class":1133},[1120,6728,1088],{"class":1141},[1120,6730,1521],{"class":1133},[1120,6732,6733,6735,6738,6741],{"class":1122,"line":1504},[1120,6734,1465],{"class":1137},[1120,6736,6737],{"class":1133}," goleak.",[1120,6739,6740],{"class":1141},"VerifyNone",[1120,6742,6743],{"class":1133},"(t)\n",[1120,6745,6746],{"class":1122,"line":1524},[1120,6747,6748],{"class":1126},"    \u002F\u002F test code\n",[1120,6750,6751],{"class":1122,"line":1537},[1120,6752,1404],{"class":1133},[895,6754],{},[903,6756,6758],{"id":6757},"q43-在go函数中为什么会发生内存泄露","Q43: 在Go函数中为什么会发生内存泄露",[892,6760,6761],{},[1042,6762,6763],{},"常见内存泄露场景：",[1290,6765,6766,6772,6778,6784],{},[1293,6767,6768,6771],{},[1042,6769,6770],{},"Goroutine 泄露","：阻塞在 channel 上无法退出",[1293,6773,6774,6777],{},[1042,6775,6776],{},"未关闭的资源","：文件句柄、网络连接、HTTP Body",[1293,6779,6780,6783],{},[1042,6781,6782],{},"缓存未清理","：全局 map 无限增长",[1293,6785,6786],{},[1042,6787,6788],{},"time.Ticker 未停止",[1112,6790,6792],{"className":1114,"code":6791,"language":1116,"meta":11,"style":11},"ticker := time.NewTicker(time.Second)\ndefer ticker.Stop()  \u002F\u002F 必须停止！\n",[936,6793,6794,6810],{"__ignoreMap":11},[1120,6795,6796,6799,6801,6804,6807],{"class":1122,"line":1123},[1120,6797,6798],{"class":1133},"ticker ",[1120,6800,1138],{"class":1137},[1120,6802,6803],{"class":1133}," time.",[1120,6805,6806],{"class":1141},"NewTicker",[1120,6808,6809],{"class":1133},"(time.Second)\n",[1120,6811,6812,6814,6817,6820,6822],{"class":1122,"line":1130},[1120,6813,6224],{"class":1137},[1120,6815,6816],{"class":1133}," ticker.",[1120,6818,6819],{"class":1141},"Stop",[1120,6821,5974],{"class":1133},[1120,6823,6824],{"class":1126},"\u002F\u002F 必须停止！\n",[895,6826],{},[898,6828,6830],{"id":6829},"四gmp-调度器","四、GMP 调度器",[903,6832,6834],{"id":6833},"q44-go的gpm如何调度","Q44: Go的GPM如何调度",[892,6836,6837],{},[1042,6838,6839],{},"GMP 组件：",[908,6841,6842,6854],{},[911,6843,6844],{},[914,6845,6846,6849,6852],{},[917,6847,6848],{"align":919},"组件",[917,6850,6851],{"align":919},"全称",[917,6853,5027],{"align":919},[925,6855,6856,6866,6877],{},[914,6857,6858,6861,6863],{},[930,6859,6860],{"align":919},"G",[930,6862,4493],{"align":919},[930,6864,6865],{"align":919},"协程",[914,6867,6868,6871,6874],{},[930,6869,6870],{"align":919},"M",[930,6872,6873],{"align":919},"Machine",[930,6875,6876],{"align":919},"操作系统线程",[914,6878,6879,6882,6885],{},[930,6880,6881],{"align":919},"P",[930,6883,6884],{"align":919},"Processor",[930,6886,6887],{"align":919},"逻辑处理器，连接 G 和 M",[892,6889,6890],{},[1042,6891,6892],{},"调度流程：",[1290,6894,6895,6898,6901,6904],{},[1293,6896,6897],{},"优先从 P 的本地队列获取 G",[1293,6899,6900],{},"本地队列空则从全局队列批量获取",[1293,6902,6903],{},"全局队列空则从其他 P 偷取（Work Stealing）",[1293,6905,6906],{},"都没有则 M 休眠",[892,6908,6909],{},[1042,6910,6911],{},"抢占式调度（Go 1.14+）：",[1667,6913,6914,6917],{},[1293,6915,6916],{},"基于信号的异步抢占",[1293,6918,6919],{},"即使没有函数调用也能被抢占",[895,6921],{},[903,6923,6925],{"id":6924},"q45-为何gpm调度要有p","Q45: 为何GPM调度要有P",[892,6927,6928],{},[1042,6929,6930],{},"P 的存在解决以下问题：",[1290,6932,6933,6939,6945,6951],{},[1293,6934,6935,6938],{},[1042,6936,6937],{},"本地队列","：减少全局锁竞争",[1293,6940,6941,6944],{},[1042,6942,6943],{},"mcache 缓存","：每个 P 有独立的内存缓存",[1293,6946,6947,6950],{},[1042,6948,6949],{},"控制并发度","：GOMAXPROCS 控制 P 数量",[1293,6952,6953,6956],{},[1042,6954,6955],{},"Work Stealing","：P 可以互相偷任务",[895,6958],{},[903,6960,6962],{"id":6961},"q46-goroutine和kernelthread之间是什么关系","Q46: Goroutine和KernelThread之间是什么关系",[892,6964,6965],{},[1042,6966,6967],{},"多对多（M:N）关系：",[1667,6969,6970,6973,6976],{},[1293,6971,6972],{},"多个 G 运行在少数 M 上",[1293,6974,6975],{},"P 作为中介连接 G 和 M",[1293,6977,6978],{},"充分利用多核，避免频繁上下文切换",[895,6980],{},[903,6982,6984],{"id":6983},"q47-g0的作用","Q47: G0的作用",[892,6986,6987],{},[1042,6988,6989],{},"G0 是每个 M（线程）的特殊 goroutine：",[892,6991,6992],{},[1042,6993,6994],{},"作用：",[1290,6996,6997,7000,7003,7006],{},[1293,6998,6999],{},"运行调度器代码",[1293,7001,7002],{},"执行 cgo、syscall",[1293,7004,7005],{},"goroutine 栈扩缩容",[1293,7007,7008],{},"执行 GC 标记等",[892,7010,7011,7013],{},[1042,7012,1665],{}," 每个 M 都有一个 G0，使用系统栈（约 8KB）",[895,7015],{},[898,7017,7019],{"id":7018},"五内存管理","五、内存管理",[903,7021,7023],{"id":7022},"q48-go语言的栈空间管理是怎么样的","Q48: Go语言的栈空间管理是怎么样的",[892,7025,7026],{},[1042,7027,7028],{},"动态栈机制：",[1667,7030,7031,7034,7037],{},[1293,7032,7033],{},"初始栈大小：2KB",[1293,7035,7036],{},"最大栈大小：1GB（64位系统）",[1293,7038,7039],{},"动态增长策略",[892,7041,7042],{},[1042,7043,7044],{},"栈扩容过程：",[1290,7046,7047,7050,7053,7056,7059],{},[1293,7048,7049],{},"检测到栈不足",[1293,7051,7052],{},"分配新栈（2 倍大小）",[1293,7054,7055],{},"复制旧栈内容",[1293,7057,7058],{},"调整栈上指针",[1293,7060,7061],{},"释放旧栈",[892,7063,7064,7067],{},[1042,7065,7066],{},"栈收缩："," GC 时检查，使用率 \u003C 1\u002F4 时收缩",[895,7069],{},[903,7071,7073],{"id":7072},"q49-go的对象在内存中是怎样分配的","Q49: Go的对象在内存中是怎样分配的",[892,7075,7076],{},[1042,7077,7078],{},"Go 使用 TCMalloc 多级缓存：",[1112,7080,7086],{"className":7081,"code":7083,"language":7084,"meta":7085},[7082],"language-text","flowchart TD\n    A[\"mcache#40;每个 P 一个，无锁#41;\"] --> B[\"mcentral#40;每个 size class 一个，有锁#41;\"]\n    B --> C[\"mheap#40;全局唯一，管理所有内存#41;\"]\n","text","mermaid",[936,7087,7083],{"__ignoreMap":11},[908,7089,7090,7100],{},[911,7091,7092],{},[914,7093,7094,7097],{},[917,7095,7096],{"align":919},"对象大小",[917,7098,7099],{"align":919},"分配方式",[925,7101,7102,7110,7118],{},[914,7103,7104,7107],{},[930,7105,7106],{"align":919},"\u003C 16B（tiny）",[930,7108,7109],{"align":919},"Tiny Allocator",[914,7111,7112,7115],{},[930,7113,7114],{"align":919},"16B ~ 32KB",[930,7116,7117],{"align":919},"mcache → mcentral",[914,7119,7120,7123],{},[930,7121,7122],{"align":919},"> 32KB",[930,7124,7125],{"align":919},"直接从 mheap 分配",[895,7127],{},[903,7129,7131],{"id":7130},"q50-go中的逃逸分析是什么","Q50: Go中的逃逸分析是什么",[892,7133,7134],{},[1042,7135,7136],{},"逃逸分析决定变量分配在栈还是堆。",[892,7138,7139],{},[1042,7140,7141],{},"查看逃逸分析：",[1112,7143,7145],{"className":5404,"code":7144,"language":5406,"meta":11,"style":11},"go build -gcflags=\"-m\" main.go\n",[936,7146,7147],{"__ignoreMap":11},[1120,7148,7149,7151,7154,7157,7160],{"class":1122,"line":1123},[1120,7150,1116],{"class":1141},[1120,7152,7153],{"class":1866}," build",[1120,7155,7156],{"class":1207}," -gcflags=",[1120,7158,7159],{"class":1866},"\"-m\"",[1120,7161,7162],{"class":1866}," main.go\n",[892,7164,7165],{},[1042,7166,7167],{},"常见逃逸场景：",[1290,7169,7170,7173,7176,7179,7185],{},[1293,7171,7172],{},"返回局部变量指针",[1293,7174,7175],{},"闭包引用",[1293,7177,7178],{},"interface{} 参数",[1293,7180,7181,7182],{},"动态大小分配 ",[936,7183,7184],{},"make([]int, n)",[1293,7186,7187],{},"切片扩容",[1112,7189,7191],{"className":1114,"code":7190,"language":1116,"meta":11,"style":11},"func escape() *int {\n    x := 42\n    return &x  \u002F\u002F x 逃逸到堆\n}\n",[936,7192,7193,7206,7215,7227],{"__ignoreMap":11},[1120,7194,7195,7197,7200,7202,7204],{"class":1122,"line":1123},[1120,7196,1440],{"class":1137},[1120,7198,7199],{"class":1141}," escape",[1120,7201,1446],{"class":1133},[1120,7203,2072],{"class":1137},[1120,7205,1334],{"class":1133},[1120,7207,7208,7210,7212],{"class":1122,"line":1130},[1120,7209,1455],{"class":1133},[1120,7211,1138],{"class":1137},[1120,7213,7214],{"class":1207}," 42\n",[1120,7216,7217,7219,7221,7224],{"class":1122,"line":1156},[1120,7218,1482],{"class":1137},[1120,7220,2019],{"class":1137},[1120,7222,7223],{"class":1133},"x  ",[1120,7225,7226],{"class":1126},"\u002F\u002F x 逃逸到堆\n",[1120,7228,7229],{"class":1122,"line":1177},[1120,7230,1404],{"class":1133},[895,7232],{},[903,7234,7236],{"id":7235},"q51-golang的内存模型中为什么小对象多了会造成gc压力","Q51: Golang的内存模型中为什么小对象多了会造成GC压力",[892,7238,7239],{},[1042,7240,7241],{},"原因分析：",[1290,7243,7244,7250,7256,7262],{},[1293,7245,7246,7249],{},[1042,7247,7248],{},"扫描开销","：GC 需要扫描所有对象",[1293,7251,7252,7255],{},[1042,7253,7254],{},"内存碎片","：小对象分散分布",[1293,7257,7258,7261],{},[1042,7259,7260],{},"分配压力","：频繁分配增加 mcache\u002Fmcentral 压力",[1293,7263,7264,7267],{},[1042,7265,7266],{},"三色标记","：每个对象都需要标记",[892,7269,7270,7273],{},[1042,7271,7272],{},"优化策略："," sync.Pool 复用、预分配、减少逃逸、合并小对象",[895,7275],{},[898,7277,7279],{"id":7278},"六垃圾回收","六、垃圾回收",[903,7281,7283],{"id":7282},"q52-golang垃圾回收算法","Q52: Golang垃圾回收算法",[892,7285,7286],{},[1042,7287,7288],{},"三色标记 + 混合写屏障",[892,7290,7291],{},[1042,7292,7293],{},"三色标记：",[1667,7295,7296,7302,7308],{},[1293,7297,7298,7301],{},[1042,7299,7300],{},"白色","：未扫描，可能是垃圾",[1293,7303,7304,7307],{},[1042,7305,7306],{},"灰色","：已扫描，引用未扫描",[1293,7309,7310,7313],{},[1042,7311,7312],{},"黑色","：已扫描完成",[892,7315,7316],{},[1042,7317,7318],{},"算法流程：",[1290,7320,7321,7324,7327,7330],{},[1293,7322,7323],{},"STW → 开启写屏障",[1293,7325,7326],{},"并发标记（三色标记）",[1293,7328,7329],{},"STW → 关闭写屏障",[1293,7331,7332],{},"并发清除",[892,7334,7335,7338],{},[1042,7336,7337],{},"混合写屏障（Go 1.8+）："," 插入屏障 + 删除屏障，无需栈重新扫描",[895,7340],{},[903,7342,7344],{"id":7343},"q53-gc的触发条件","Q53: GC的触发条件",[908,7346,7347,7356],{},[911,7348,7349],{},[914,7350,7351,7354],{},[917,7352,7353],{"align":919},"触发条件",[917,7355,5027],{"align":919},[925,7357,7358,7366,7374,7384],{},[914,7359,7360,7363],{},[930,7361,7362],{"align":919},"堆内存增长",[930,7364,7365],{"align":919},"达到 GOGC 阈值（默认 100%，即翻倍）",[914,7367,7368,7371],{},[930,7369,7370],{"align":919},"定时触发",[930,7372,7373],{"align":919},"超过 2 分钟没有 GC",[914,7375,7376,7379],{},[930,7377,7378],{"align":919},"手动触发",[930,7380,7381],{"align":919},[936,7382,7383],{},"runtime.GC()",[914,7385,7386,7389],{},[930,7387,7388],{"align":919},"内存限制",[930,7390,7391],{"align":919},"GOMEMLIMIT（Go 1.19+）",[1112,7393,7395],{"className":5404,"code":7394,"language":5406,"meta":11,"style":11},"GOGC=100   # 默认值，堆内存增长 100% 触发 GC\nGOGC=200   # 降低 GC 频率\nGOGC=off   # 关闭 GC（不推荐）\n",[936,7396,7397,7409,7421],{"__ignoreMap":11},[1120,7398,7399,7402,7404,7406],{"class":1122,"line":1123},[1120,7400,7401],{"class":1133},"GOGC",[1120,7403,2094],{"class":1137},[1120,7405,2675],{"class":1866},[1120,7407,7408],{"class":1126},"   # 默认值，堆内存增长 100% 触发 GC\n",[1120,7410,7411,7413,7415,7418],{"class":1122,"line":1130},[1120,7412,7401],{"class":1133},[1120,7414,2094],{"class":1137},[1120,7416,7417],{"class":1866},"200",[1120,7419,7420],{"class":1126},"   # 降低 GC 频率\n",[1120,7422,7423,7425,7427,7430],{"class":1122,"line":1156},[1120,7424,7401],{"class":1133},[1120,7426,2094],{"class":1137},[1120,7428,7429],{"class":1866},"off",[1120,7431,7432],{"class":1126},"   # 关闭 GC（不推荐）\n",[895,7434],{},[903,7436,7438],{"id":7437},"q54-gc-过程中的-stw","Q54: GC 过程中的 STW",[892,7440,7441],{},[1042,7442,7443],{},"两次短暂的 STW：",[1112,7445,7448],{"className":7446,"code":7447,"language":7084},[7082],"Mark Setup (STW 1)    ~10-30μs   开启写屏障\nConcurrent Mark                   后台标记\nMark Termination (STW 2) ~60-90μs 关闭写屏障\nConcurrent Sweep                  清理\n",[936,7449,7447],{"__ignoreMap":11},[892,7451,7452],{},"总 STW 时间通常 \u003C 1ms。",[895,7454],{},[903,7456,7458],{"id":7457},"q55-如何优化-gc","Q55: 如何优化 GC",[1290,7460,7461,7470,7476,7484,7489],{},[1293,7462,7463,1045,7466,7469],{},[1042,7464,7465],{},"调整 GOGC",[936,7467,7468],{},"GOGC=200"," 减少 GC 频率",[1293,7471,7472,7475],{},[1042,7473,7474],{},"使用 GOMEMLIMIT","（Go 1.19+）",[1293,7477,7478,1045,7481],{},[1042,7479,7480],{},"复用对象",[936,7482,7483],{},"sync.Pool",[1293,7485,7486],{},[1042,7487,7488],{},"预分配切片",[1293,7490,7491],{},[1042,7492,7493],{},"减少逃逸",[895,7495],{},[898,7497,7499],{"id":7498},"七标准库与实战","七、标准库与实战",[903,7501,7503],{"id":7502},"q56-go中的http包的实现原理","Q56: Go中的http包的实现原理",[892,7505,7506],{},[1042,7507,7508],{},"核心组件：",[1112,7510,7512],{"className":1114,"code":7511,"language":1116,"meta":11,"style":11},"type Handler interface {\n    ServeHTTP(ResponseWriter, *Request)\n}\n\ntype ServeMux struct {\n    mu    sync.RWMutex\n    m     map[string]muxEntry\n}\n",[936,7513,7514,7525,7544,7548,7552,7563,7575,7591],{"__ignoreMap":11},[1120,7515,7516,7518,7521,7523],{"class":1122,"line":1123},[1120,7517,1325],{"class":1137},[1120,7519,7520],{"class":1141}," Handler",[1120,7522,2203],{"class":1137},[1120,7524,1334],{"class":1133},[1120,7526,7527,7530,7532,7535,7537,7539,7542],{"class":1122,"line":1130},[1120,7528,7529],{"class":1141},"    ServeHTTP",[1120,7531,1145],{"class":1133},[1120,7533,7534],{"class":1141},"ResponseWriter",[1120,7536,949],{"class":1133},[1120,7538,1380],{"class":1137},[1120,7540,7541],{"class":1141},"Request",[1120,7543,2591],{"class":1133},[1120,7545,7546],{"class":1122,"line":1156},[1120,7547,1404],{"class":1133},[1120,7549,7550],{"class":1122,"line":1177},[1120,7551,1181],{"emptyLinePlaceholder":1180},[1120,7553,7554,7556,7559,7561],{"class":1122,"line":1184},[1120,7555,1325],{"class":1137},[1120,7557,7558],{"class":1141}," ServeMux",[1120,7560,1331],{"class":1137},[1120,7562,1334],{"class":1133},[1120,7564,7565,7568,7570,7572],{"class":1122,"line":1190},[1120,7566,7567],{"class":1133},"    mu    ",[1120,7569,5890],{"class":1141},[1120,7571,2167],{"class":1133},[1120,7573,7574],{"class":1141},"RWMutex\n",[1120,7576,7577,7580,7582,7584,7586,7588],{"class":1122,"line":1221},[1120,7578,7579],{"class":1133},"    m     ",[1120,7581,1233],{"class":1137},[1120,7583,1236],{"class":1133},[1120,7585,1022],{"class":1137},[1120,7587,1241],{"class":1133},[1120,7589,7590],{"class":1141},"muxEntry\n",[1120,7592,7593],{"class":1122,"line":1251},[1120,7594,1404],{"class":1133},[892,7596,7597],{},[1042,7598,7599],{},"工作流程：",[1290,7601,7602,7605,7608,7611,7614,7617],{},[1293,7603,7604],{},"ListenAndServe 监听端口",[1293,7606,7607],{},"Accept 接受连接",[1293,7609,7610],{},"为每个连接启动 goroutine",[1293,7612,7613],{},"解析 HTTP 请求",[1293,7615,7616],{},"路由匹配 → 调用 Handler",[1293,7618,7619],{},"写入响应",[895,7621],{},[903,7623,7625],{"id":7624},"q57-syncpool-的作用和原理","Q57: sync.Pool 的作用和原理",[892,7627,7628,7630],{},[1042,7629,6994],{}," 对象复用，减少 GC 压力",[1112,7632,7634],{"className":1114,"code":7633,"language":1116,"meta":11,"style":11},"var pool = sync.Pool{\n    New: func() interface{} {\n        return new(bytes.Buffer)\n    },\n}\n\nbuf := pool.Get().(*bytes.Buffer)\nbuf.Reset()\n\u002F\u002F 使用 buf...\npool.Put(buf)\n",[936,7635,7636,7656,7670,7689,7694,7698,7702,7728,7738,7743],{"__ignoreMap":11},[1120,7637,7638,7640,7643,7645,7648,7650,7653],{"class":1122,"line":1123},[1120,7639,2066],{"class":1137},[1120,7641,7642],{"class":1133}," pool ",[1120,7644,2094],{"class":1137},[1120,7646,7647],{"class":1141}," sync",[1120,7649,2167],{"class":1133},[1120,7651,7652],{"class":1141},"Pool",[1120,7654,7655],{"class":1133},"{\n",[1120,7657,7658,7661,7663,7665,7667],{"class":1122,"line":1130},[1120,7659,7660],{"class":1133},"    New: ",[1120,7662,1440],{"class":1137},[1120,7664,1446],{"class":1133},[1120,7666,2088],{"class":1137},[1120,7668,7669],{"class":1133},"{} {\n",[1120,7671,7672,7675,7677,7679,7682,7684,7687],{"class":1122,"line":1156},[1120,7673,7674],{"class":1137},"        return",[1120,7676,1142],{"class":1141},[1120,7678,1145],{"class":1133},[1120,7680,7681],{"class":1141},"bytes",[1120,7683,2167],{"class":1133},[1120,7685,7686],{"class":1141},"Buffer",[1120,7688,2591],{"class":1133},[1120,7690,7691],{"class":1122,"line":1177},[1120,7692,7693],{"class":1133},"    },\n",[1120,7695,7696],{"class":1122,"line":1184},[1120,7697,1404],{"class":1133},[1120,7699,7700],{"class":1122,"line":1190},[1120,7701,1181],{"emptyLinePlaceholder":1180},[1120,7703,7704,7707,7709,7712,7715,7718,7720,7722,7724,7726],{"class":1122,"line":1221},[1120,7705,7706],{"class":1133},"buf ",[1120,7708,1138],{"class":1137},[1120,7710,7711],{"class":1133}," pool.",[1120,7713,7714],{"class":1141},"Get",[1120,7716,7717],{"class":1133},"().(",[1120,7719,1380],{"class":1137},[1120,7721,7681],{"class":1141},[1120,7723,2167],{"class":1133},[1120,7725,7686],{"class":1141},[1120,7727,2591],{"class":1133},[1120,7729,7730,7733,7736],{"class":1122,"line":1251},[1120,7731,7732],{"class":1133},"buf.",[1120,7734,7735],{"class":1141},"Reset",[1120,7737,2796],{"class":1133},[1120,7739,7740],{"class":1122,"line":1504},[1120,7741,7742],{"class":1126},"\u002F\u002F 使用 buf...\n",[1120,7744,7745,7748,7751],{"class":1122,"line":1524},[1120,7746,7747],{"class":1133},"pool.",[1120,7749,7750],{"class":1141},"Put",[1120,7752,7753],{"class":1133},"(buf)\n",[892,7755,7756,7759],{},[1042,7757,7758],{},"注意："," Pool 中的对象可能在任意时刻被 GC 回收",[895,7761],{},[903,7763,7765],{"id":7764},"q58-synconce-的实现原理","Q58: sync.Once 的实现原理",[1112,7767,7769],{"className":1114,"code":7768,"language":1116,"meta":11,"style":11},"type Once struct {\n    done uint32\n    m    Mutex\n}\n\nfunc (o *Once) Do(f func()) {\n    if atomic.LoadUint32(&o.done) == 1 {\n        return  \u002F\u002F 快速路径\n    }\n    o.m.Lock()\n    defer o.m.Unlock()\n    if o.done == 0 {\n        defer atomic.StoreUint32(&o.done, 1)\n        f()\n    }\n}\n",[936,7770,7771,7782,7790,7798,7802,7806,7834,7857,7864,7868,7878,7890,7903,7923,7930,7934],{"__ignoreMap":11},[1120,7772,7773,7775,7778,7780],{"class":1122,"line":1123},[1120,7774,1325],{"class":1137},[1120,7776,7777],{"class":1141}," Once",[1120,7779,1331],{"class":1137},[1120,7781,1334],{"class":1133},[1120,7783,7784,7787],{"class":1122,"line":1130},[1120,7785,7786],{"class":1133},"    done ",[1120,7788,7789],{"class":1137},"uint32\n",[1120,7791,7792,7795],{"class":1122,"line":1156},[1120,7793,7794],{"class":1133},"    m    ",[1120,7796,7797],{"class":1141},"Mutex\n",[1120,7799,7800],{"class":1122,"line":1177},[1120,7801,1404],{"class":1133},[1120,7803,7804],{"class":1122,"line":1184},[1120,7805,1181],{"emptyLinePlaceholder":1180},[1120,7807,7808,7810,7812,7815,7817,7820,7822,7824,7826,7829,7831],{"class":1122,"line":1190},[1120,7809,1440],{"class":1137},[1120,7811,2508],{"class":1133},[1120,7813,7814],{"class":1515},"o ",[1120,7816,1380],{"class":1137},[1120,7818,7819],{"class":1141},"Once",[1120,7821,2519],{"class":1133},[1120,7823,6275],{"class":1141},[1120,7825,1145],{"class":1133},[1120,7827,7828],{"class":1515},"f",[1120,7830,1468],{"class":1137},[1120,7832,7833],{"class":1133},"()) {\n",[1120,7835,7836,7838,7840,7843,7845,7847,7850,7852,7855],{"class":1122,"line":1221},[1120,7837,5352],{"class":1137},[1120,7839,5337],{"class":1133},[1120,7841,7842],{"class":1141},"LoadUint32",[1120,7844,1145],{"class":1133},[1120,7846,2385],{"class":1137},[1120,7848,7849],{"class":1133},"o.done) ",[1120,7851,1907],{"class":1137},[1120,7853,7854],{"class":1207}," 1",[1120,7856,1334],{"class":1133},[1120,7858,7859,7861],{"class":1122,"line":1251},[1120,7860,7674],{"class":1137},[1120,7862,7863],{"class":1126},"  \u002F\u002F 快速路径\n",[1120,7865,7866],{"class":1122,"line":1504},[1120,7867,5381],{"class":1133},[1120,7869,7870,7873,7876],{"class":1122,"line":1524},[1120,7871,7872],{"class":1133},"    o.m.",[1120,7874,7875],{"class":1141},"Lock",[1120,7877,2796],{"class":1133},[1120,7879,7880,7882,7885,7888],{"class":1122,"line":1537},[1120,7881,1465],{"class":1137},[1120,7883,7884],{"class":1133}," o.m.",[1120,7886,7887],{"class":1141},"Unlock",[1120,7889,2796],{"class":1133},[1120,7891,7892,7894,7897,7899,7901],{"class":1122,"line":1548},[1120,7893,5352],{"class":1137},[1120,7895,7896],{"class":1133}," o.done ",[1120,7898,1907],{"class":1137},[1120,7900,5494],{"class":1207},[1120,7902,1334],{"class":1133},[1120,7904,7905,7907,7909,7912,7914,7916,7919,7921],{"class":1122,"line":2333},[1120,7906,5732],{"class":1137},[1120,7908,5337],{"class":1133},[1120,7910,7911],{"class":1141},"StoreUint32",[1120,7913,1145],{"class":1133},[1120,7915,2385],{"class":1137},[1120,7917,7918],{"class":1133},"o.done, ",[1120,7920,5369],{"class":1207},[1120,7922,2591],{"class":1133},[1120,7924,7925,7928],{"class":1122,"line":2339},[1120,7926,7927],{"class":1141},"        f",[1120,7929,2796],{"class":1133},[1120,7931,7932],{"class":1122,"line":2344},[1120,7933,5381],{"class":1133},[1120,7935,7936],{"class":1122,"line":2349},[1120,7937,1404],{"class":1133},[895,7939],{},[903,7941,7943],{"id":7942},"q59-go-中如何实现单例模式","Q59: Go 中如何实现单例模式",[1112,7945,7947],{"className":1114,"code":7946,"language":1116,"meta":11,"style":11},"var (\n    instance *Singleton\n    once     sync.Once\n)\n\nfunc GetInstance() *Singleton {\n    once.Do(func() {\n        instance = &Singleton{}\n    })\n    return instance\n}\n",[936,7948,7949,7956,7966,7978,7982,7986,8002,8015,8029,8034,8041],{"__ignoreMap":11},[1120,7950,7951,7953],{"class":1122,"line":1123},[1120,7952,2066],{"class":1137},[1120,7954,7955],{"class":1133}," (\n",[1120,7957,7958,7961,7963],{"class":1122,"line":1130},[1120,7959,7960],{"class":1133},"    instance ",[1120,7962,1380],{"class":1137},[1120,7964,7965],{"class":1141},"Singleton\n",[1120,7967,7968,7971,7973,7975],{"class":1122,"line":1156},[1120,7969,7970],{"class":1133},"    once     ",[1120,7972,5890],{"class":1141},[1120,7974,2167],{"class":1133},[1120,7976,7977],{"class":1141},"Once\n",[1120,7979,7980],{"class":1122,"line":1177},[1120,7981,2591],{"class":1133},[1120,7983,7984],{"class":1122,"line":1184},[1120,7985,1181],{"emptyLinePlaceholder":1180},[1120,7987,7988,7990,7993,7995,7997,8000],{"class":1122,"line":1190},[1120,7989,1440],{"class":1137},[1120,7991,7992],{"class":1141}," GetInstance",[1120,7994,1446],{"class":1133},[1120,7996,1380],{"class":1137},[1120,7998,7999],{"class":1141},"Singleton",[1120,8001,1334],{"class":1133},[1120,8003,8004,8007,8009,8011,8013],{"class":1122,"line":1221},[1120,8005,8006],{"class":1133},"    once.",[1120,8008,6275],{"class":1141},[1120,8010,1145],{"class":1133},[1120,8012,1440],{"class":1137},[1120,8014,2729],{"class":1133},[1120,8016,8017,8020,8022,8024,8026],{"class":1122,"line":1251},[1120,8018,8019],{"class":1133},"        instance ",[1120,8021,2094],{"class":1137},[1120,8023,2019],{"class":1137},[1120,8025,7999],{"class":1141},[1120,8027,8028],{"class":1133},"{}\n",[1120,8030,8031],{"class":1122,"line":1504},[1120,8032,8033],{"class":1133},"    })\n",[1120,8035,8036,8038],{"class":1122,"line":1524},[1120,8037,1482],{"class":1137},[1120,8039,8040],{"class":1133}," instance\n",[1120,8042,8043],{"class":1122,"line":1537},[1120,8044,1404],{"class":1133},[895,8046],{},[903,8048,8050],{"id":8049},"q60-pprof-性能分析怎么用","Q60: pprof 性能分析怎么用",[1112,8052,8054],{"className":1114,"code":8053,"language":1116,"meta":11,"style":11},"import _ \"net\u002Fhttp\u002Fpprof\"\n\ngo http.ListenAndServe(\":6060\", nil)\n",[936,8055,8056,8068,8072],{"__ignoreMap":11},[1120,8057,8058,8060,8062,8064,8066],{"class":1122,"line":1123},[1120,8059,5827],{"class":1137},[1120,8061,5830],{"class":1133},[1120,8063,2301],{"class":1866},[1120,8065,5835],{"class":1141},[1120,8067,5838],{"class":1866},[1120,8069,8070],{"class":1122,"line":1130},[1120,8071,1181],{"emptyLinePlaceholder":1180},[1120,8073,8074,8076,8078,8080,8082,8084,8086,8088],{"class":1122,"line":1156},[1120,8075,1116],{"class":1137},[1120,8077,5845],{"class":1133},[1120,8079,5848],{"class":1141},[1120,8081,1145],{"class":1133},[1120,8083,5853],{"class":1866},[1120,8085,949],{"class":1133},[1120,8087,2686],{"class":1207},[1120,8089,2591],{"class":1133},[1112,8091,8093],{"className":5404,"code":8092,"language":5406,"meta":11,"style":11},"# CPU 分析\ngo tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fprofile?seconds=30\n\n# 内存分析\ngo tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap\n\n# Goroutine 分析\ngo tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fgoroutine\n\n# 常用命令\ntop, list, web, svg\n",[936,8094,8095,8100,8116,8120,8125,8136,8140,8145,8156,8160,8165],{"__ignoreMap":11},[1120,8096,8097],{"class":1122,"line":1123},[1120,8098,8099],{"class":1126},"# CPU 分析\n",[1120,8101,8102,8104,8107,8110,8113],{"class":1122,"line":1130},[1120,8103,1116],{"class":1141},[1120,8105,8106],{"class":1866}," tool",[1120,8108,8109],{"class":1866}," pprof",[1120,8111,8112],{"class":1866}," http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fprofile?seconds=",[1120,8114,8115],{"class":1207},"30\n",[1120,8117,8118],{"class":1122,"line":1156},[1120,8119,1181],{"emptyLinePlaceholder":1180},[1120,8121,8122],{"class":1122,"line":1177},[1120,8123,8124],{"class":1126},"# 内存分析\n",[1120,8126,8127,8129,8131,8133],{"class":1122,"line":1184},[1120,8128,1116],{"class":1141},[1120,8130,8106],{"class":1866},[1120,8132,8109],{"class":1866},[1120,8134,8135],{"class":1866}," http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap\n",[1120,8137,8138],{"class":1122,"line":1190},[1120,8139,1181],{"emptyLinePlaceholder":1180},[1120,8141,8142],{"class":1122,"line":1221},[1120,8143,8144],{"class":1126},"# Goroutine 分析\n",[1120,8146,8147,8149,8151,8153],{"class":1122,"line":1251},[1120,8148,1116],{"class":1141},[1120,8150,8106],{"class":1866},[1120,8152,8109],{"class":1866},[1120,8154,8155],{"class":1866}," http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fgoroutine\n",[1120,8157,8158],{"class":1122,"line":1504},[1120,8159,1181],{"emptyLinePlaceholder":1180},[1120,8161,8162],{"class":1122,"line":1524},[1120,8163,8164],{"class":1126},"# 常用命令\n",[1120,8166,8167,8170,8173,8176],{"class":1122,"line":1537},[1120,8168,8169],{"class":1141},"top,",[1120,8171,8172],{"class":1866}," list,",[1120,8174,8175],{"class":1866}," web,",[1120,8177,8178],{"class":1866}," svg\n",[895,8180],{},[898,8182,8184],{"id":8183},"八项目实战","八、项目实战",[903,8186,8188],{"id":8187},"q61-gin-中间件的实现原理","Q61: Gin 中间件的实现原理",[892,8190,8191],{},[1042,8192,8193],{},"洋葱模型，基于责任链模式：",[1112,8195,8197],{"className":1114,"code":8196,"language":1116,"meta":11,"style":11},"type Context struct {\n    handlers HandlersChain  \u002F\u002F []HandlerFunc\n    index    int8           \u002F\u002F 当前执行的 handler 索引\n}\n\nfunc (c *Context) Next() {\n    c.index++\n    for c.index \u003C int8(len(c.handlers)) {\n        c.handlers[c.index](c)\n        c.index++\n    }\n}\n",[936,8198,8199,8210,8221,8231,8235,8239,8259,8267,8286,8307,8314,8318],{"__ignoreMap":11},[1120,8200,8201,8203,8206,8208],{"class":1122,"line":1123},[1120,8202,1325],{"class":1137},[1120,8204,8205],{"class":1141}," Context",[1120,8207,1331],{"class":1137},[1120,8209,1334],{"class":1133},[1120,8211,8212,8215,8218],{"class":1122,"line":1130},[1120,8213,8214],{"class":1133},"    handlers ",[1120,8216,8217],{"class":1141},"HandlersChain",[1120,8219,8220],{"class":1126},"  \u002F\u002F []HandlerFunc\n",[1120,8222,8223,8226,8228],{"class":1122,"line":1156},[1120,8224,8225],{"class":1133},"    index    ",[1120,8227,952],{"class":1137},[1120,8229,8230],{"class":1126},"           \u002F\u002F 当前执行的 handler 索引\n",[1120,8232,8233],{"class":1122,"line":1177},[1120,8234,1404],{"class":1133},[1120,8236,8237],{"class":1122,"line":1184},[1120,8238,1181],{"emptyLinePlaceholder":1180},[1120,8240,8241,8243,8245,8248,8250,8252,8254,8257],{"class":1122,"line":1190},[1120,8242,1440],{"class":1137},[1120,8244,2508],{"class":1133},[1120,8246,8247],{"class":1515},"c ",[1120,8249,1380],{"class":1137},[1120,8251,6058],{"class":1141},[1120,8253,2519],{"class":1133},[1120,8255,8256],{"class":1141},"Next",[1120,8258,2729],{"class":1133},[1120,8260,8261,8264],{"class":1122,"line":1221},[1120,8262,8263],{"class":1133},"    c.index",[1120,8265,8266],{"class":1137},"++\n",[1120,8268,8269,8271,8274,8276,8279,8281,8283],{"class":1122,"line":1251},[1120,8270,6535],{"class":1137},[1120,8272,8273],{"class":1133}," c.index ",[1120,8275,3364],{"class":1137},[1120,8277,8278],{"class":1137}," int8",[1120,8280,1145],{"class":1133},[1120,8282,4182],{"class":1141},[1120,8284,8285],{"class":1133},"(c.handlers)) {\n",[1120,8287,8288,8291,8294,8296,8299,8301,8304],{"class":1122,"line":1504},[1120,8289,8290],{"class":1133},"        c.",[1120,8292,8293],{"class":1141},"handlers",[1120,8295,1236],{"class":1133},[1120,8297,8298],{"class":1141},"c",[1120,8300,2167],{"class":1133},[1120,8302,8303],{"class":1141},"index",[1120,8305,8306],{"class":1133},"](c)\n",[1120,8308,8309,8312],{"class":1122,"line":1524},[1120,8310,8311],{"class":1133},"        c.index",[1120,8313,8266],{"class":1137},[1120,8315,8316],{"class":1122,"line":1537},[1120,8317,5381],{"class":1133},[1120,8319,8320],{"class":1122,"line":1548},[1120,8321,1404],{"class":1133},[892,8323,8324],{},[1042,8325,3114],{},[1112,8327,8330],{"className":8328,"code":8329,"language":7084,"meta":7085},[7082],"flowchart LR\n    A[\"请求\"] --> B[\"Middleware1\"] --> C[\"Middleware2\"] --> D[\"Handler\"] --> E[\"Middleware2\"] --> F[\"Middleware1\"] --> G[\"响应\"]\n",[936,8331,8329],{"__ignoreMap":11},[895,8333],{},[903,8335,8337],{"id":8336},"q62-gorm-的-hook-机制","Q62: GORM 的 Hook 机制",[1112,8339,8341],{"className":1114,"code":8340,"language":1116,"meta":11,"style":11},"\u002F\u002F 创建前\nfunc (u *User) BeforeCreate(tx *gorm.DB) error {\n    u.Password = hashPassword(u.Password)\n    return nil\n}\n\n\u002F\u002F 更新前\nfunc (u *User) BeforeUpdate(tx *gorm.DB) error {\n    if tx.Statement.Changed(\"Password\") {\n        u.Password = hashPassword(u.Password)\n    }\n    return nil\n}\n",[936,8342,8343,8348,8387,8400,8406,8410,8414,8419,8454,8471,8482,8486,8492],{"__ignoreMap":11},[1120,8344,8345],{"class":1122,"line":1123},[1120,8346,8347],{"class":1126},"\u002F\u002F 创建前\n",[1120,8349,8350,8352,8354,8357,8359,8361,8363,8366,8368,8371,8373,8376,8378,8381,8383,8385],{"class":1122,"line":1130},[1120,8351,1440],{"class":1137},[1120,8353,2508],{"class":1133},[1120,8355,8356],{"class":1515},"u ",[1120,8358,1380],{"class":1137},[1120,8360,1989],{"class":1141},[1120,8362,2519],{"class":1133},[1120,8364,8365],{"class":1141},"BeforeCreate",[1120,8367,1145],{"class":1133},[1120,8369,8370],{"class":1515},"tx",[1120,8372,6355],{"class":1137},[1120,8374,8375],{"class":1141},"gorm",[1120,8377,2167],{"class":1133},[1120,8379,8380],{"class":1141},"DB",[1120,8382,2519],{"class":1133},[1120,8384,2857],{"class":1137},[1120,8386,1334],{"class":1133},[1120,8388,8389,8392,8394,8397],{"class":1122,"line":1156},[1120,8390,8391],{"class":1133},"    u.Password ",[1120,8393,2094],{"class":1137},[1120,8395,8396],{"class":1141}," hashPassword",[1120,8398,8399],{"class":1133},"(u.Password)\n",[1120,8401,8402,8404],{"class":1122,"line":1177},[1120,8403,1482],{"class":1137},[1120,8405,2078],{"class":1207},[1120,8407,8408],{"class":1122,"line":1184},[1120,8409,1404],{"class":1133},[1120,8411,8412],{"class":1122,"line":1190},[1120,8413,1181],{"emptyLinePlaceholder":1180},[1120,8415,8416],{"class":1122,"line":1221},[1120,8417,8418],{"class":1126},"\u002F\u002F 更新前\n",[1120,8420,8421,8423,8425,8427,8429,8431,8433,8436,8438,8440,8442,8444,8446,8448,8450,8452],{"class":1122,"line":1251},[1120,8422,1440],{"class":1137},[1120,8424,2508],{"class":1133},[1120,8426,8356],{"class":1515},[1120,8428,1380],{"class":1137},[1120,8430,1989],{"class":1141},[1120,8432,2519],{"class":1133},[1120,8434,8435],{"class":1141},"BeforeUpdate",[1120,8437,1145],{"class":1133},[1120,8439,8370],{"class":1515},[1120,8441,6355],{"class":1137},[1120,8443,8375],{"class":1141},[1120,8445,2167],{"class":1133},[1120,8447,8380],{"class":1141},[1120,8449,2519],{"class":1133},[1120,8451,2857],{"class":1137},[1120,8453,1334],{"class":1133},[1120,8455,8456,8458,8461,8464,8466,8469],{"class":1122,"line":1504},[1120,8457,5352],{"class":1137},[1120,8459,8460],{"class":1133}," tx.Statement.",[1120,8462,8463],{"class":1141},"Changed",[1120,8465,1145],{"class":1133},[1120,8467,8468],{"class":1866},"\"Password\"",[1120,8470,1521],{"class":1133},[1120,8472,8473,8476,8478,8480],{"class":1122,"line":1524},[1120,8474,8475],{"class":1133},"        u.Password ",[1120,8477,2094],{"class":1137},[1120,8479,8396],{"class":1141},[1120,8481,8399],{"class":1133},[1120,8483,8484],{"class":1122,"line":1537},[1120,8485,5381],{"class":1133},[1120,8487,8488,8490],{"class":1122,"line":1548},[1120,8489,1482],{"class":1137},[1120,8491,2078],{"class":1207},[1120,8493,8494],{"class":1122,"line":2333},[1120,8495,1404],{"class":1133},[892,8497,8498],{},[1042,8499,8500],{},"Hook 顺序：",[1667,8502,8503,8506],{},[1293,8504,8505],{},"创建：BeforeSave → BeforeCreate → 插入 → AfterCreate → AfterSave",[1293,8507,8508],{},"更新：BeforeSave → BeforeUpdate → 更新 → AfterUpdate → AfterSave",[895,8510],{},[903,8512,8514],{"id":8513},"q63-如何实现分布式锁","Q63: 如何实现分布式锁",[892,8516,8517],{},[1042,8518,8519],{},"Redis 分布式锁：",[1112,8521,8523],{"className":1114,"code":8522,"language":1116,"meta":11,"style":11},"\u002F\u002F 加锁\nfunc TryLock(ctx context.Context, key, value string, ttl time.Duration) bool {\n    ok, _ := rdb.SetNX(ctx, key, value, ttl).Result()\n    return ok\n}\n\n\u002F\u002F 解锁（Lua 保证原子性）\nfunc Unlock(ctx context.Context, key, value string) bool {\n    script := redis.NewScript(`\n        if redis.call('get', KEYS[1]) == ARGV[1] then\n            return redis.call('del', KEYS[1])\n        end\n        return 0\n    `)\n    result, _ := script.Run(ctx, rdb, []string{key}, value).Int()\n    return result == 1\n}\n",[936,8524,8525,8530,8579,8600,8607,8611,8615,8620,8653,8671,8676,8681,8686,8691,8698,8724,8736],{"__ignoreMap":11},[1120,8526,8527],{"class":1122,"line":1123},[1120,8528,8529],{"class":1126},"\u002F\u002F 加锁\n",[1120,8531,8532,8534,8537,8539,8541,8543,8545,8547,8549,8552,8554,8557,8560,8562,8565,8568,8570,8573,8575,8577],{"class":1122,"line":1130},[1120,8533,1440],{"class":1137},[1120,8535,8536],{"class":1141}," TryLock",[1120,8538,1145],{"class":1133},[1120,8540,6467],{"class":1515},[1120,8542,6524],{"class":1141},[1120,8544,2167],{"class":1133},[1120,8546,6058],{"class":1141},[1120,8548,949],{"class":1133},[1120,8550,8551],{"class":1515},"key",[1120,8553,949],{"class":1133},[1120,8555,8556],{"class":1515},"value",[1120,8558,8559],{"class":1137}," string",[1120,8561,949],{"class":1133},[1120,8563,8564],{"class":1515},"ttl",[1120,8566,8567],{"class":1141}," time",[1120,8569,2167],{"class":1133},[1120,8571,8572],{"class":1141},"Duration",[1120,8574,2519],{"class":1133},[1120,8576,938],{"class":1137},[1120,8578,1334],{"class":1133},[1120,8580,8581,8584,8586,8589,8592,8595,8598],{"class":1122,"line":1156},[1120,8582,8583],{"class":1133},"    ok, _ ",[1120,8585,1138],{"class":1137},[1120,8587,8588],{"class":1133}," rdb.",[1120,8590,8591],{"class":1141},"SetNX",[1120,8593,8594],{"class":1133},"(ctx, key, value, ttl).",[1120,8596,8597],{"class":1141},"Result",[1120,8599,2796],{"class":1133},[1120,8601,8602,8604],{"class":1122,"line":1177},[1120,8603,1482],{"class":1137},[1120,8605,8606],{"class":1133}," ok\n",[1120,8608,8609],{"class":1122,"line":1184},[1120,8610,1404],{"class":1133},[1120,8612,8613],{"class":1122,"line":1190},[1120,8614,1181],{"emptyLinePlaceholder":1180},[1120,8616,8617],{"class":1122,"line":1221},[1120,8618,8619],{"class":1126},"\u002F\u002F 解锁（Lua 保证原子性）\n",[1120,8621,8622,8624,8627,8629,8631,8633,8635,8637,8639,8641,8643,8645,8647,8649,8651],{"class":1122,"line":1251},[1120,8623,1440],{"class":1137},[1120,8625,8626],{"class":1141}," Unlock",[1120,8628,1145],{"class":1133},[1120,8630,6467],{"class":1515},[1120,8632,6524],{"class":1141},[1120,8634,2167],{"class":1133},[1120,8636,6058],{"class":1141},[1120,8638,949],{"class":1133},[1120,8640,8551],{"class":1515},[1120,8642,949],{"class":1133},[1120,8644,8556],{"class":1515},[1120,8646,8559],{"class":1137},[1120,8648,2519],{"class":1133},[1120,8650,938],{"class":1137},[1120,8652,1334],{"class":1133},[1120,8654,8655,8658,8660,8663,8666,8668],{"class":1122,"line":1504},[1120,8656,8657],{"class":1133},"    script ",[1120,8659,1138],{"class":1137},[1120,8661,8662],{"class":1133}," redis.",[1120,8664,8665],{"class":1141},"NewScript",[1120,8667,1145],{"class":1133},[1120,8669,8670],{"class":1866},"`\n",[1120,8672,8673],{"class":1122,"line":1524},[1120,8674,8675],{"class":1866},"        if redis.call('get', KEYS[1]) == ARGV[1] then\n",[1120,8677,8678],{"class":1122,"line":1537},[1120,8679,8680],{"class":1866},"            return redis.call('del', KEYS[1])\n",[1120,8682,8683],{"class":1122,"line":1548},[1120,8684,8685],{"class":1866},"        end\n",[1120,8687,8688],{"class":1122,"line":2333},[1120,8689,8690],{"class":1866},"        return 0\n",[1120,8692,8693,8696],{"class":1122,"line":2339},[1120,8694,8695],{"class":1866},"    `",[1120,8697,2591],{"class":1133},[1120,8699,8700,8703,8705,8708,8711,8714,8716,8719,8722],{"class":1122,"line":2344},[1120,8701,8702],{"class":1133},"    result, _ ",[1120,8704,1138],{"class":1137},[1120,8706,8707],{"class":1133}," script.",[1120,8709,8710],{"class":1141},"Run",[1120,8712,8713],{"class":1133},"(ctx, rdb, []",[1120,8715,1022],{"class":1137},[1120,8717,8718],{"class":1133},"{key}, value).",[1120,8720,8721],{"class":1141},"Int",[1120,8723,2796],{"class":1133},[1120,8725,8726,8728,8731,8733],{"class":1122,"line":2349},[1120,8727,1482],{"class":1137},[1120,8729,8730],{"class":1133}," result ",[1120,8732,1907],{"class":1137},[1120,8734,8735],{"class":1207}," 1\n",[1120,8737,8738],{"class":1122,"line":2355},[1120,8739,1404],{"class":1133},[895,8741],{},[903,8743,8745],{"id":8744},"q64-缓存穿透击穿雪崩如何解决","Q64: 缓存穿透、击穿、雪崩如何解决",[908,8747,8748,8760],{},[911,8749,8750],{},[914,8751,8752,8755,8757],{},[917,8753,8754],{"align":919},"问题",[917,8756,2847],{"align":919},[917,8758,8759],{"align":919},"解决方案",[925,8761,8762,8773,8784],{},[914,8763,8764,8767,8770],{},[930,8765,8766],{"align":919},"穿透",[930,8768,8769],{"align":919},"查询不存在的数据",[930,8771,8772],{"align":919},"布隆过滤器、缓存空值",[914,8774,8775,8778,8781],{},[930,8776,8777],{"align":919},"击穿",[930,8779,8780],{"align":919},"热点 key 过期",[930,8782,8783],{"align":919},"互斥锁、永不过期 + 异步更新",[914,8785,8786,8789,8792],{},[930,8787,8788],{"align":919},"雪崩",[930,8790,8791],{"align":919},"大量 key 同时过期",[930,8793,8794],{"align":919},"随机过期时间、多级缓存",[895,8796],{},[903,8798,8800],{"id":8799},"q65-如何实现服务熔断","Q65: 如何实现服务熔断",[1112,8802,8804],{"className":1114,"code":8803,"language":1116,"meta":11,"style":11},"import \"github.com\u002Fsony\u002Fgobreaker\"\n\ncb := gobreaker.NewCircuitBreaker(gobreaker.Settings{\n    Name:        \"my-service\",\n    MaxRequests: 3,\n    Timeout:     30 * time.Second,\n    ReadyToTrip: func(counts gobreaker.Counts) bool {\n        failureRatio := float64(counts.TotalFailures) \u002F float64(counts.Requests)\n        return counts.Requests >= 3 && failureRatio >= 0.6\n    },\n})\n\nresult, err := cb.Execute(func() (interface{}, error) {\n    return doRequest()\n})\n",[936,8805,8806,8818,8822,8847,8858,8868,8881,8907,8927,8950,8954,8959,8963,8990,8999],{"__ignoreMap":11},[1120,8807,8808,8810,8813,8816],{"class":1122,"line":1123},[1120,8809,5827],{"class":1137},[1120,8811,8812],{"class":1866}," \"",[1120,8814,8815],{"class":1141},"github.com\u002Fsony\u002Fgobreaker",[1120,8817,5838],{"class":1866},[1120,8819,8820],{"class":1122,"line":1130},[1120,8821,1181],{"emptyLinePlaceholder":1180},[1120,8823,8824,8827,8829,8832,8835,8837,8840,8842,8845],{"class":1122,"line":1156},[1120,8825,8826],{"class":1133},"cb ",[1120,8828,1138],{"class":1137},[1120,8830,8831],{"class":1133}," gobreaker.",[1120,8833,8834],{"class":1141},"NewCircuitBreaker",[1120,8836,1145],{"class":1133},[1120,8838,8839],{"class":1141},"gobreaker",[1120,8841,2167],{"class":1133},[1120,8843,8844],{"class":1141},"Settings",[1120,8846,7655],{"class":1133},[1120,8848,8849,8852,8855],{"class":1122,"line":1177},[1120,8850,8851],{"class":1133},"    Name:        ",[1120,8853,8854],{"class":1866},"\"my-service\"",[1120,8856,8857],{"class":1133},",\n",[1120,8859,8860,8863,8866],{"class":1122,"line":1184},[1120,8861,8862],{"class":1133},"    MaxRequests: ",[1120,8864,8865],{"class":1207},"3",[1120,8867,8857],{"class":1133},[1120,8869,8870,8873,8876,8878],{"class":1122,"line":1190},[1120,8871,8872],{"class":1133},"    Timeout:     ",[1120,8874,8875],{"class":1207},"30",[1120,8877,6355],{"class":1137},[1120,8879,8880],{"class":1133}," time.Second,\n",[1120,8882,8883,8886,8888,8890,8893,8896,8898,8901,8903,8905],{"class":1122,"line":1221},[1120,8884,8885],{"class":1133},"    ReadyToTrip: ",[1120,8887,1440],{"class":1137},[1120,8889,1145],{"class":1133},[1120,8891,8892],{"class":1515},"counts",[1120,8894,8895],{"class":1141}," gobreaker",[1120,8897,2167],{"class":1133},[1120,8899,8900],{"class":1141},"Counts",[1120,8902,2519],{"class":1133},[1120,8904,938],{"class":1137},[1120,8906,1334],{"class":1133},[1120,8908,8909,8912,8914,8917,8920,8922,8924],{"class":1122,"line":1251},[1120,8910,8911],{"class":1133},"        failureRatio ",[1120,8913,1138],{"class":1137},[1120,8915,8916],{"class":1137}," float64",[1120,8918,8919],{"class":1133},"(counts.TotalFailures) ",[1120,8921,3424],{"class":1137},[1120,8923,8916],{"class":1137},[1120,8925,8926],{"class":1133},"(counts.Requests)\n",[1120,8928,8929,8931,8934,8937,8939,8942,8945,8947],{"class":1122,"line":1504},[1120,8930,7674],{"class":1137},[1120,8932,8933],{"class":1133}," counts.Requests ",[1120,8935,8936],{"class":1137},">=",[1120,8938,3414],{"class":1207},[1120,8940,8941],{"class":1137}," &&",[1120,8943,8944],{"class":1133}," failureRatio ",[1120,8946,8936],{"class":1137},[1120,8948,8949],{"class":1207}," 0.6\n",[1120,8951,8952],{"class":1122,"line":1524},[1120,8953,7693],{"class":1133},[1120,8955,8956],{"class":1122,"line":1537},[1120,8957,8958],{"class":1133},"})\n",[1120,8960,8961],{"class":1122,"line":1548},[1120,8962,1181],{"emptyLinePlaceholder":1180},[1120,8964,8965,8968,8970,8973,8976,8978,8980,8982,8984,8986,8988],{"class":1122,"line":2333},[1120,8966,8967],{"class":1133},"result, err ",[1120,8969,1138],{"class":1137},[1120,8971,8972],{"class":1133}," cb.",[1120,8974,8975],{"class":1141},"Execute",[1120,8977,1145],{"class":1133},[1120,8979,1440],{"class":1137},[1120,8981,1512],{"class":1133},[1120,8983,2088],{"class":1137},[1120,8985,5630],{"class":1133},[1120,8987,2857],{"class":1137},[1120,8989,1521],{"class":1133},[1120,8991,8992,8994,8997],{"class":1122,"line":2339},[1120,8993,1482],{"class":1137},[1120,8995,8996],{"class":1141}," doRequest",[1120,8998,2796],{"class":1133},[1120,9000,9001],{"class":1122,"line":2344},[1120,9002,8958],{"class":1133},[892,9004,9005,9008],{},[1042,9006,9007],{},"熔断器状态："," Closed（正常）→ Open（熔断）→ Half-Open（测试）",[895,9010],{},[903,9012,9014],{"id":9013},"q66-grpc-和-http-的区别","Q66: gRPC 和 HTTP 的区别",[908,9016,9017,9029],{},[911,9018,9019],{},[914,9020,9021,9023,9026],{},[917,9022,1063],{"align":919},[917,9024,9025],{"align":919},"gRPC",[917,9027,9028],{"align":919},"HTTP\u002FREST",[925,9030,9031,9042,9053,9061,9072],{},[914,9032,9033,9036,9039],{},[930,9034,9035],{"align":919},"协议",[930,9037,9038],{"align":919},"HTTP\u002F2",[930,9040,9041],{"align":919},"HTTP\u002F1.1",[914,9043,9044,9047,9050],{},[930,9045,9046],{"align":919},"序列化",[930,9048,9049],{"align":919},"Protobuf（二进制）",[930,9051,9052],{"align":919},"JSON（文本）",[914,9054,9055,9057,9059],{},[930,9056,3225],{"align":919},[930,9058,3264],{"align":919},[930,9060,3910],{"align":919},[914,9062,9063,9066,9069],{},[930,9064,9065],{"align":919},"流式传输",[930,9067,9068],{"align":919},"原生支持",[930,9070,9071],{"align":919},"需 WebSocket",[914,9073,9074,9077,9080],{},[930,9075,9076],{"align":919},"浏览器",[930,9078,9079],{"align":919},"需 grpc-web",[930,9081,9068],{"align":919},[892,9083,9084,9087],{},[1042,9085,9086],{},"选择："," 内部服务用 gRPC，对外 API 用 REST",[895,9089],{},[903,9091,9093],{"id":9092},"q67-如何保证消息不丢失","Q67: 如何保证消息不丢失",[892,9095,9096],{},[1042,9097,9098],{},"三个环节：",[1290,9100,9101,9107,9113],{},[1293,9102,9103,9106],{},[1042,9104,9105],{},"生产者确认","：等待 broker ACK",[1293,9108,9109,9112],{},[1042,9110,9111],{},"MQ 持久化","：消息落盘",[1293,9114,9115,9118],{},[1042,9116,9117],{},"消费者确认","：手动 ACK",[892,9120,9121],{},[1042,9122,9123],{},"幂等性处理：",[1112,9125,9127],{"className":1114,"code":9126,"language":1116,"meta":11,"style":11},"func processOrder(orderID string) error {\n    if processed, _ := redis.Get(\"processed:\" + orderID); processed != \"\" {\n        return nil  \u002F\u002F 已处理\n    }\n    \n    if err := doProcess(orderID); err != nil {\n        return err\n    }\n    \n    redis.Set(\"processed:\"+orderID, \"1\", 24*time.Hour)\n    return nil\n}\n",[936,9128,9129,9149,9180,9189,9193,9197,9217,9223,9227,9231,9260,9266],{"__ignoreMap":11},[1120,9130,9131,9133,9136,9138,9141,9143,9145,9147],{"class":1122,"line":1123},[1120,9132,1440],{"class":1137},[1120,9134,9135],{"class":1141}," processOrder",[1120,9137,1145],{"class":1133},[1120,9139,9140],{"class":1515},"orderID",[1120,9142,8559],{"class":1137},[1120,9144,2519],{"class":1133},[1120,9146,2857],{"class":1137},[1120,9148,1334],{"class":1133},[1120,9150,9151,9153,9156,9158,9160,9162,9164,9167,9170,9173,9175,9178],{"class":1122,"line":1130},[1120,9152,5352],{"class":1137},[1120,9154,9155],{"class":1133}," processed, _ ",[1120,9157,1138],{"class":1137},[1120,9159,8662],{"class":1133},[1120,9161,7714],{"class":1141},[1120,9163,1145],{"class":1133},[1120,9165,9166],{"class":1866},"\"processed:\"",[1120,9168,9169],{"class":1137}," +",[1120,9171,9172],{"class":1133}," orderID); processed ",[1120,9174,2244],{"class":1137},[1120,9176,9177],{"class":1866}," \"\"",[1120,9179,1334],{"class":1133},[1120,9181,9182,9184,9186],{"class":1122,"line":1156},[1120,9183,7674],{"class":1137},[1120,9185,2111],{"class":1207},[1120,9187,9188],{"class":1126},"  \u002F\u002F 已处理\n",[1120,9190,9191],{"class":1122,"line":1177},[1120,9192,5381],{"class":1133},[1120,9194,9195],{"class":1122,"line":1184},[1120,9196,2811],{"class":1133},[1120,9198,9199,9201,9203,9205,9208,9211,9213,9215],{"class":1122,"line":1190},[1120,9200,5352],{"class":1137},[1120,9202,2241],{"class":1133},[1120,9204,1138],{"class":1137},[1120,9206,9207],{"class":1141}," doProcess",[1120,9209,9210],{"class":1133},"(orderID); err ",[1120,9212,2244],{"class":1137},[1120,9214,2111],{"class":1207},[1120,9216,1334],{"class":1133},[1120,9218,9219,9221],{"class":1122,"line":1221},[1120,9220,7674],{"class":1137},[1120,9222,2255],{"class":1133},[1120,9224,9225],{"class":1122,"line":1251},[1120,9226,5381],{"class":1133},[1120,9228,9229],{"class":1122,"line":1504},[1120,9230,2811],{"class":1133},[1120,9232,9233,9236,9239,9241,9243,9245,9248,9250,9252,9255,9257],{"class":1122,"line":1524},[1120,9234,9235],{"class":1133},"    redis.",[1120,9237,9238],{"class":1141},"Set",[1120,9240,1145],{"class":1133},[1120,9242,9166],{"class":1866},[1120,9244,3236],{"class":1137},[1120,9246,9247],{"class":1133},"orderID, ",[1120,9249,2948],{"class":1866},[1120,9251,949],{"class":1133},[1120,9253,9254],{"class":1207},"24",[1120,9256,1380],{"class":1137},[1120,9258,9259],{"class":1133},"time.Hour)\n",[1120,9261,9262,9264],{"class":1122,"line":1537},[1120,9263,1482],{"class":1137},[1120,9265,2078],{"class":1207},[1120,9267,9268],{"class":1122,"line":1548},[1120,9269,1404],{"class":1133},[895,9271],{},[898,9273,9275],{"id":9274},"九gin-框架深入","九、Gin 框架深入",[903,9277,9279],{"id":9278},"q68-gin-和-nethttp-的关系","Q68: Gin 和 net\u002Fhttp 的关系",[892,9281,9282],{},[1042,9283,9284],{},"Gin 是基于 net\u002Fhttp 的封装：",[1112,9286,9288],{"className":1114,"code":9287,"language":1116,"meta":11,"style":11},"\u002F\u002F Gin 的 Engine 实现了 http.Handler 接口\ntype Engine struct {\n    \u002F\u002F ...\n}\n\nfunc (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {\n    \u002F\u002F 处理请求\n}\n\n\u002F\u002F 可以作为 http.Handler 使用\nhttp.ListenAndServe(\":8080\", engine)\n",[936,9289,9290,9295,9306,9311,9315,9319,9366,9371,9375,9379,9384],{"__ignoreMap":11},[1120,9291,9292],{"class":1122,"line":1123},[1120,9293,9294],{"class":1126},"\u002F\u002F Gin 的 Engine 实现了 http.Handler 接口\n",[1120,9296,9297,9299,9302,9304],{"class":1122,"line":1130},[1120,9298,1325],{"class":1137},[1120,9300,9301],{"class":1141}," Engine",[1120,9303,1331],{"class":1137},[1120,9305,1334],{"class":1133},[1120,9307,9308],{"class":1122,"line":1156},[1120,9309,9310],{"class":1126},"    \u002F\u002F ...\n",[1120,9312,9313],{"class":1122,"line":1177},[1120,9314,1404],{"class":1133},[1120,9316,9317],{"class":1122,"line":1184},[1120,9318,1181],{"emptyLinePlaceholder":1180},[1120,9320,9321,9323,9325,9328,9330,9333,9335,9338,9340,9343,9346,9348,9350,9352,9355,9357,9360,9362,9364],{"class":1122,"line":1190},[1120,9322,1440],{"class":1137},[1120,9324,2508],{"class":1133},[1120,9326,9327],{"class":1515},"engine ",[1120,9329,1380],{"class":1137},[1120,9331,9332],{"class":1141},"Engine",[1120,9334,2519],{"class":1133},[1120,9336,9337],{"class":1141},"ServeHTTP",[1120,9339,1145],{"class":1133},[1120,9341,9342],{"class":1515},"w",[1120,9344,9345],{"class":1141}," http",[1120,9347,2167],{"class":1133},[1120,9349,7534],{"class":1141},[1120,9351,949],{"class":1133},[1120,9353,9354],{"class":1515},"req",[1120,9356,6355],{"class":1137},[1120,9358,9359],{"class":1141},"http",[1120,9361,2167],{"class":1133},[1120,9363,7541],{"class":1141},[1120,9365,1521],{"class":1133},[1120,9367,9368],{"class":1122,"line":1221},[1120,9369,9370],{"class":1126},"    \u002F\u002F 处理请求\n",[1120,9372,9373],{"class":1122,"line":1251},[1120,9374,1404],{"class":1133},[1120,9376,9377],{"class":1122,"line":1504},[1120,9378,1181],{"emptyLinePlaceholder":1180},[1120,9380,9381],{"class":1122,"line":1524},[1120,9382,9383],{"class":1126},"\u002F\u002F 可以作为 http.Handler 使用\n",[1120,9385,9386,9389,9391,9393,9396],{"class":1122,"line":1537},[1120,9387,9388],{"class":1133},"http.",[1120,9390,5848],{"class":1141},[1120,9392,1145],{"class":1133},[1120,9394,9395],{"class":1866},"\":8080\"",[1120,9397,9398],{"class":1133},", engine)\n",[892,9400,9401],{},[1042,9402,9403],{},"Gin 在 net\u002Fhttp 基础上增加了：",[1667,9405,9406,9409,9412,9415],{},[1293,9407,9408],{},"高性能路由（基数树）",[1293,9410,9411],{},"中间件机制",[1293,9413,9414],{},"参数绑定",[1293,9416,9417],{},"错误处理",[895,9419],{},[903,9421,9423],{"id":9422},"q69-gin-中间件原理和执行顺序","Q69: Gin 中间件原理和执行顺序",[892,9425,9426],{},[1042,9427,9428],{},"洋葱模型：",[1112,9430,9433],{"className":9431,"code":9432,"language":7084,"meta":7085},[7082],"flowchart LR\n    Req[\"请求\"] --> M1A[\"M1#40;前#41;\"] --> M2A[\"M2#40;前#41;\"] --> M3A[\"M3#40;前#41;\"] --> H[\"Handler\"]\n    H --> M3B[\"M3#40;后#41;\"] --> M2B[\"M2#40;后#41;\"] --> M1B[\"M1#40;后#41;\"] --> Resp[\"响应\"]\n",[936,9434,9432],{"__ignoreMap":11},[892,9436,9437],{},[1042,9438,3114],{},[1112,9440,9442],{"className":1114,"code":9441,"language":1116,"meta":11,"style":11},"func Logger() gin.HandlerFunc {\n    return func(c *gin.Context) {\n        start := time.Now()\n        \n        c.Next()  \u002F\u002F 执行后续处理\n        \n        latency := time.Since(start)\n        log.Printf(\"耗时: %v\", latency)\n    }\n}\n",[936,9443,9444,9463,9483,9497,9502,9513,9517,9532,9551,9555],{"__ignoreMap":11},[1120,9445,9446,9448,9451,9453,9456,9458,9461],{"class":1122,"line":1123},[1120,9447,1440],{"class":1137},[1120,9449,9450],{"class":1141}," Logger",[1120,9452,1446],{"class":1133},[1120,9454,9455],{"class":1141},"gin",[1120,9457,2167],{"class":1133},[1120,9459,9460],{"class":1141},"HandlerFunc",[1120,9462,1334],{"class":1133},[1120,9464,9465,9467,9469,9471,9473,9475,9477,9479,9481],{"class":1122,"line":1130},[1120,9466,1482],{"class":1137},[1120,9468,1468],{"class":1137},[1120,9470,1145],{"class":1133},[1120,9472,8298],{"class":1515},[1120,9474,6355],{"class":1137},[1120,9476,9455],{"class":1141},[1120,9478,2167],{"class":1133},[1120,9480,6058],{"class":1141},[1120,9482,1521],{"class":1133},[1120,9484,9485,9488,9490,9492,9495],{"class":1122,"line":1156},[1120,9486,9487],{"class":1133},"        start ",[1120,9489,1138],{"class":1137},[1120,9491,6803],{"class":1133},[1120,9493,9494],{"class":1141},"Now",[1120,9496,2796],{"class":1133},[1120,9498,9499],{"class":1122,"line":1177},[1120,9500,9501],{"class":1133},"        \n",[1120,9503,9504,9506,9508,9510],{"class":1122,"line":1184},[1120,9505,8290],{"class":1133},[1120,9507,8256],{"class":1141},[1120,9509,5974],{"class":1133},[1120,9511,9512],{"class":1126},"\u002F\u002F 执行后续处理\n",[1120,9514,9515],{"class":1122,"line":1190},[1120,9516,9501],{"class":1133},[1120,9518,9519,9522,9524,9526,9529],{"class":1122,"line":1221},[1120,9520,9521],{"class":1133},"        latency ",[1120,9523,1138],{"class":1137},[1120,9525,6803],{"class":1133},[1120,9527,9528],{"class":1141},"Since",[1120,9530,9531],{"class":1133},"(start)\n",[1120,9533,9534,9537,9539,9541,9544,9546,9548],{"class":1122,"line":1251},[1120,9535,9536],{"class":1133},"        log.",[1120,9538,2767],{"class":1141},[1120,9540,1145],{"class":1133},[1120,9542,9543],{"class":1866},"\"耗时: ",[1120,9545,2775],{"class":1207},[1120,9547,2301],{"class":1866},[1120,9549,9550],{"class":1133},", latency)\n",[1120,9552,9553],{"class":1122,"line":1504},[1120,9554,5381],{"class":1133},[1120,9556,9557],{"class":1122,"line":1524},[1120,9558,1404],{"class":1133},[892,9560,9561],{},[1042,9562,9563],{},"关键方法：",[1667,9565,9566,9572,9578],{},[1293,9567,9568,9571],{},[936,9569,9570],{},"c.Next()","：执行后续 handler",[1293,9573,9574,9577],{},[936,9575,9576],{},"c.Abort()","：终止后续执行",[1293,9579,9580,9583],{},[936,9581,9582],{},"c.AbortWithStatus()","：终止并返回状态码",[895,9585],{},[903,9587,9589],{"id":9588},"q70-如何实现一个鉴权中间件","Q70: 如何实现一个鉴权中间件",[1112,9591,9593],{"className":1114,"code":9592,"language":1116,"meta":11,"style":11},"func AuthMiddleware() gin.HandlerFunc {\n    return func(c *gin.Context) {\n        token := c.GetHeader(\"Authorization\")\n        \n        \u002F\u002F 1. 检查 Token 是否存在\n        if token == \"\" {\n            c.AbortWithStatusJSON(401, gin.H{\"error\": \"未授权\"})\n            return\n        }\n        \n        \u002F\u002F 2. 验证 Token\n        claims, err := jwt.ParseToken(token)\n        if err != nil {\n            c.AbortWithStatusJSON(401, gin.H{\"error\": \"Token 无效\"})\n            return\n        }\n        \n        \u002F\u002F 3. 将用户信息存入 Context\n        c.Set(\"userID\", claims.UserID)\n        c.Set(\"role\", claims.Role)\n        \n        c.Next()\n    }\n}\n",[936,9594,9595,9612,9632,9652,9656,9661,9674,9709,9714,9718,9722,9727,9743,9755,9784,9788,9792,9796,9801,9815,9829,9833,9841,9846],{"__ignoreMap":11},[1120,9596,9597,9599,9602,9604,9606,9608,9610],{"class":1122,"line":1123},[1120,9598,1440],{"class":1137},[1120,9600,9601],{"class":1141}," AuthMiddleware",[1120,9603,1446],{"class":1133},[1120,9605,9455],{"class":1141},[1120,9607,2167],{"class":1133},[1120,9609,9460],{"class":1141},[1120,9611,1334],{"class":1133},[1120,9613,9614,9616,9618,9620,9622,9624,9626,9628,9630],{"class":1122,"line":1130},[1120,9615,1482],{"class":1137},[1120,9617,1468],{"class":1137},[1120,9619,1145],{"class":1133},[1120,9621,8298],{"class":1515},[1120,9623,6355],{"class":1137},[1120,9625,9455],{"class":1141},[1120,9627,2167],{"class":1133},[1120,9629,6058],{"class":1141},[1120,9631,1521],{"class":1133},[1120,9633,9634,9637,9639,9642,9645,9647,9650],{"class":1122,"line":1156},[1120,9635,9636],{"class":1133},"        token ",[1120,9638,1138],{"class":1137},[1120,9640,9641],{"class":1133}," c.",[1120,9643,9644],{"class":1141},"GetHeader",[1120,9646,1145],{"class":1133},[1120,9648,9649],{"class":1866},"\"Authorization\"",[1120,9651,2591],{"class":1133},[1120,9653,9654],{"class":1122,"line":1177},[1120,9655,9501],{"class":1133},[1120,9657,9658],{"class":1122,"line":1184},[1120,9659,9660],{"class":1126},"        \u002F\u002F 1. 检查 Token 是否存在\n",[1120,9662,9663,9665,9668,9670,9672],{"class":1122,"line":1190},[1120,9664,2742],{"class":1137},[1120,9666,9667],{"class":1133}," token ",[1120,9669,1907],{"class":1137},[1120,9671,9177],{"class":1866},[1120,9673,1334],{"class":1133},[1120,9675,9676,9679,9682,9684,9687,9689,9691,9693,9696,9698,9701,9704,9707],{"class":1122,"line":1221},[1120,9677,9678],{"class":1133},"            c.",[1120,9680,9681],{"class":1141},"AbortWithStatusJSON",[1120,9683,1145],{"class":1133},[1120,9685,9686],{"class":1207},"401",[1120,9688,949],{"class":1133},[1120,9690,9455],{"class":1141},[1120,9692,2167],{"class":1133},[1120,9694,9695],{"class":1141},"H",[1120,9697,1863],{"class":1133},[1120,9699,9700],{"class":1866},"\"error\"",[1120,9702,9703],{"class":1133},": ",[1120,9705,9706],{"class":1866},"\"未授权\"",[1120,9708,8958],{"class":1133},[1120,9710,9711],{"class":1122,"line":1251},[1120,9712,9713],{"class":1137},"            return\n",[1120,9715,9716],{"class":1122,"line":1504},[1120,9717,2801],{"class":1133},[1120,9719,9720],{"class":1122,"line":1524},[1120,9721,9501],{"class":1133},[1120,9723,9724],{"class":1122,"line":1537},[1120,9725,9726],{"class":1126},"        \u002F\u002F 2. 验证 Token\n",[1120,9728,9729,9732,9734,9737,9740],{"class":1122,"line":1548},[1120,9730,9731],{"class":1133},"        claims, err ",[1120,9733,1138],{"class":1137},[1120,9735,9736],{"class":1133}," jwt.",[1120,9738,9739],{"class":1141},"ParseToken",[1120,9741,9742],{"class":1133},"(token)\n",[1120,9744,9745,9747,9749,9751,9753],{"class":1122,"line":2333},[1120,9746,2742],{"class":1137},[1120,9748,2241],{"class":1133},[1120,9750,2244],{"class":1137},[1120,9752,2111],{"class":1207},[1120,9754,1334],{"class":1133},[1120,9756,9757,9759,9761,9763,9765,9767,9769,9771,9773,9775,9777,9779,9782],{"class":1122,"line":2339},[1120,9758,9678],{"class":1133},[1120,9760,9681],{"class":1141},[1120,9762,1145],{"class":1133},[1120,9764,9686],{"class":1207},[1120,9766,949],{"class":1133},[1120,9768,9455],{"class":1141},[1120,9770,2167],{"class":1133},[1120,9772,9695],{"class":1141},[1120,9774,1863],{"class":1133},[1120,9776,9700],{"class":1866},[1120,9778,9703],{"class":1133},[1120,9780,9781],{"class":1866},"\"Token 无效\"",[1120,9783,8958],{"class":1133},[1120,9785,9786],{"class":1122,"line":2344},[1120,9787,9713],{"class":1137},[1120,9789,9790],{"class":1122,"line":2349},[1120,9791,2801],{"class":1133},[1120,9793,9794],{"class":1122,"line":2355},[1120,9795,9501],{"class":1133},[1120,9797,9798],{"class":1122,"line":2372},[1120,9799,9800],{"class":1126},"        \u002F\u002F 3. 将用户信息存入 Context\n",[1120,9802,9803,9805,9807,9809,9812],{"class":1122,"line":2391},[1120,9804,8290],{"class":1133},[1120,9806,9238],{"class":1141},[1120,9808,1145],{"class":1133},[1120,9810,9811],{"class":1866},"\"userID\"",[1120,9813,9814],{"class":1133},", claims.UserID)\n",[1120,9816,9817,9819,9821,9823,9826],{"class":1122,"line":2402},[1120,9818,8290],{"class":1133},[1120,9820,9238],{"class":1141},[1120,9822,1145],{"class":1133},[1120,9824,9825],{"class":1866},"\"role\"",[1120,9827,9828],{"class":1133},", claims.Role)\n",[1120,9830,9831],{"class":1122,"line":3100},[1120,9832,9501],{"class":1133},[1120,9834,9835,9837,9839],{"class":1122,"line":3106},[1120,9836,8290],{"class":1133},[1120,9838,8256],{"class":1141},[1120,9840,2796],{"class":1133},[1120,9842,9844],{"class":1122,"line":9843},23,[1120,9845,5381],{"class":1133},[1120,9847,9849],{"class":1122,"line":9848},24,[1120,9850,1404],{"class":1133},[895,9852],{},[903,9854,9856],{"id":9855},"q71-gin-如何处理-panic","Q71: Gin 如何处理 panic",[892,9858,9859],{},[1042,9860,9861],{},"内置 Recovery 中间件：",[1112,9863,9865],{"className":1114,"code":9864,"language":1116,"meta":11,"style":11},"r := gin.Default()  \u002F\u002F 包含 Logger 和 Recovery\n\n\u002F\u002F 手动添加\nr.Use(gin.Recovery())\n\n\u002F\u002F 自定义 Recovery\nr.Use(gin.CustomRecovery(func(c *gin.Context, err interface{}) {\n    \u002F\u002F 记录日志\n    log.Printf(\"Panic: %v\", err)\n    \n    \u002F\u002F 返回错误响应\n    c.AbortWithStatusJSON(500, gin.H{\n        \"error\": \"服务器内部错误\",\n    })\n}))\n",[936,9866,9867,9885,9889,9894,9910,9914,9919,9956,9961,9979,9983,9988,10010,10022,10026],{"__ignoreMap":11},[1120,9868,9869,9872,9874,9877,9880,9882],{"class":1122,"line":1123},[1120,9870,9871],{"class":1133},"r ",[1120,9873,1138],{"class":1137},[1120,9875,9876],{"class":1133}," gin.",[1120,9878,9879],{"class":1141},"Default",[1120,9881,5974],{"class":1133},[1120,9883,9884],{"class":1126},"\u002F\u002F 包含 Logger 和 Recovery\n",[1120,9886,9887],{"class":1122,"line":1130},[1120,9888,1181],{"emptyLinePlaceholder":1180},[1120,9890,9891],{"class":1122,"line":1156},[1120,9892,9893],{"class":1126},"\u002F\u002F 手动添加\n",[1120,9895,9896,9899,9902,9905,9908],{"class":1122,"line":1177},[1120,9897,9898],{"class":1133},"r.",[1120,9900,9901],{"class":1141},"Use",[1120,9903,9904],{"class":1133},"(gin.",[1120,9906,9907],{"class":1141},"Recovery",[1120,9909,5813],{"class":1133},[1120,9911,9912],{"class":1122,"line":1184},[1120,9913,1181],{"emptyLinePlaceholder":1180},[1120,9915,9916],{"class":1122,"line":1190},[1120,9917,9918],{"class":1126},"\u002F\u002F 自定义 Recovery\n",[1120,9920,9921,9923,9925,9927,9930,9932,9934,9936,9938,9940,9942,9944,9946,9948,9951,9953],{"class":1122,"line":1221},[1120,9922,9898],{"class":1133},[1120,9924,9901],{"class":1141},[1120,9926,9904],{"class":1133},[1120,9928,9929],{"class":1141},"CustomRecovery",[1120,9931,1145],{"class":1133},[1120,9933,1440],{"class":1137},[1120,9935,1145],{"class":1133},[1120,9937,8298],{"class":1515},[1120,9939,6355],{"class":1137},[1120,9941,9455],{"class":1141},[1120,9943,2167],{"class":1133},[1120,9945,6058],{"class":1141},[1120,9947,949],{"class":1133},[1120,9949,9950],{"class":1515},"err",[1120,9952,2203],{"class":1137},[1120,9954,9955],{"class":1133},"{}) {\n",[1120,9957,9958],{"class":1122,"line":1251},[1120,9959,9960],{"class":1126},"    \u002F\u002F 记录日志\n",[1120,9962,9963,9966,9968,9970,9973,9975,9977],{"class":1122,"line":1504},[1120,9964,9965],{"class":1133},"    log.",[1120,9967,2767],{"class":1141},[1120,9969,1145],{"class":1133},[1120,9971,9972],{"class":1866},"\"Panic: ",[1120,9974,2775],{"class":1207},[1120,9976,2301],{"class":1866},[1120,9978,2304],{"class":1133},[1120,9980,9981],{"class":1122,"line":1524},[1120,9982,2811],{"class":1133},[1120,9984,9985],{"class":1122,"line":1537},[1120,9986,9987],{"class":1126},"    \u002F\u002F 返回错误响应\n",[1120,9989,9990,9993,9995,9997,10000,10002,10004,10006,10008],{"class":1122,"line":1548},[1120,9991,9992],{"class":1133},"    c.",[1120,9994,9681],{"class":1141},[1120,9996,1145],{"class":1133},[1120,9998,9999],{"class":1207},"500",[1120,10001,949],{"class":1133},[1120,10003,9455],{"class":1141},[1120,10005,2167],{"class":1133},[1120,10007,9695],{"class":1141},[1120,10009,7655],{"class":1133},[1120,10011,10012,10015,10017,10020],{"class":1122,"line":2333},[1120,10013,10014],{"class":1866},"        \"error\"",[1120,10016,9703],{"class":1133},[1120,10018,10019],{"class":1866},"\"服务器内部错误\"",[1120,10021,8857],{"class":1133},[1120,10023,10024],{"class":1122,"line":2339},[1120,10025,8033],{"class":1133},[1120,10027,10028],{"class":1122,"line":2344},[1120,10029,10030],{"class":1133},"}))\n",[895,10032],{},[903,10034,10036],{"id":10035},"q72-http-请求的生命周期","Q72: HTTP 请求的生命周期",[1112,10038,10041],{"className":10039,"code":10040,"language":7084,"meta":7085},[7082],"flowchart TD\n    A[\"1. 请求进入\"] --> A2[\"net\u002Fhttp 接收\"]\n    A2 --> B[\"2. Engine.ServeHTTP#40;#41;\"] --> B2[\"从连接池获取 Context\"]\n    B2 --> C[\"3. 路由匹配\"] --> C2[\"基数树查找\"]\n    C2 --> D[\"4. 执行中间件链\"] --> D2[\"handlers[0:n]\"]\n    D2 --> E[\"5. 参数绑定\"] --> E2[\"Query\u002FJSON\u002FForm\"]\n    E2 --> F[\"6. 业务处理\"] --> F2[\"Controller\"]\n    F2 --> G[\"7. 响应写入\"] --> G2[\"c.JSON#40;#41; \u002F c.String#40;#41;\"]\n    G2 --> H[\"8. Context 回收\"] --> H2[\"放回连接池\"]\n",[936,10042,10040],{"__ignoreMap":11},[895,10044],{},[903,10046,10048],{"id":10047},"q73-gin-参数校验","Q73: Gin 参数校验",[1112,10050,10052],{"className":1114,"code":10051,"language":1116,"meta":11,"style":11},"type CreateUserReq struct {\n    Username string `json:\"username\" binding:\"required,min=3,max=20\"`\n    Email    string `json:\"email\" binding:\"required,email\"`\n    Age      int    `json:\"age\" binding:\"gte=18,lte=100\"`\n    Password string `json:\"password\" binding:\"required,min=6\"`\n}\n\nfunc CreateUser(c *gin.Context) {\n    var req CreateUserReq\n    \n    if err := c.ShouldBindJSON(&req); err != nil {\n        \u002F\u002F 自定义错误处理\n        c.JSON(400, gin.H{\n            \"error\": translateError(err),\n        })\n        return\n    }\n    \n    \u002F\u002F 业务逻辑...\n}\n",[936,10053,10054,10065,10075,10085,10095,10105,10109,10113,10134,10145,10149,10175,10180,10202,10215,10220,10225,10229,10233,10238],{"__ignoreMap":11},[1120,10055,10056,10058,10061,10063],{"class":1122,"line":1123},[1120,10057,1325],{"class":1137},[1120,10059,10060],{"class":1141}," CreateUserReq",[1120,10062,1331],{"class":1137},[1120,10064,1334],{"class":1133},[1120,10066,10067,10070,10072],{"class":1122,"line":1130},[1120,10068,10069],{"class":1133},"    Username ",[1120,10071,1022],{"class":1137},[1120,10073,10074],{"class":1866}," `json:\"username\" binding:\"required,min=3,max=20\"`\n",[1120,10076,10077,10080,10082],{"class":1122,"line":1156},[1120,10078,10079],{"class":1133},"    Email    ",[1120,10081,1022],{"class":1137},[1120,10083,10084],{"class":1866}," `json:\"email\" binding:\"required,email\"`\n",[1120,10086,10087,10090,10092],{"class":1122,"line":1177},[1120,10088,10089],{"class":1133},"    Age      ",[1120,10091,948],{"class":1137},[1120,10093,10094],{"class":1866},"    `json:\"age\" binding:\"gte=18,lte=100\"`\n",[1120,10096,10097,10100,10102],{"class":1122,"line":1184},[1120,10098,10099],{"class":1133},"    Password ",[1120,10101,1022],{"class":1137},[1120,10103,10104],{"class":1866}," `json:\"password\" binding:\"required,min=6\"`\n",[1120,10106,10107],{"class":1122,"line":1190},[1120,10108,1404],{"class":1133},[1120,10110,10111],{"class":1122,"line":1221},[1120,10112,1181],{"emptyLinePlaceholder":1180},[1120,10114,10115,10117,10120,10122,10124,10126,10128,10130,10132],{"class":1122,"line":1251},[1120,10116,1440],{"class":1137},[1120,10118,10119],{"class":1141}," CreateUser",[1120,10121,1145],{"class":1133},[1120,10123,8298],{"class":1515},[1120,10125,6355],{"class":1137},[1120,10127,9455],{"class":1141},[1120,10129,2167],{"class":1133},[1120,10131,6058],{"class":1141},[1120,10133,1521],{"class":1133},[1120,10135,10136,10139,10142],{"class":1122,"line":1504},[1120,10137,10138],{"class":1137},"    var",[1120,10140,10141],{"class":1133}," req ",[1120,10143,10144],{"class":1141},"CreateUserReq\n",[1120,10146,10147],{"class":1122,"line":1524},[1120,10148,2811],{"class":1133},[1120,10150,10151,10153,10155,10157,10159,10162,10164,10166,10169,10171,10173],{"class":1122,"line":1537},[1120,10152,5352],{"class":1137},[1120,10154,2241],{"class":1133},[1120,10156,1138],{"class":1137},[1120,10158,9641],{"class":1133},[1120,10160,10161],{"class":1141},"ShouldBindJSON",[1120,10163,1145],{"class":1133},[1120,10165,2385],{"class":1137},[1120,10167,10168],{"class":1133},"req); err ",[1120,10170,2244],{"class":1137},[1120,10172,2111],{"class":1207},[1120,10174,1334],{"class":1133},[1120,10176,10177],{"class":1122,"line":1548},[1120,10178,10179],{"class":1126},"        \u002F\u002F 自定义错误处理\n",[1120,10181,10182,10184,10187,10189,10192,10194,10196,10198,10200],{"class":1122,"line":2333},[1120,10183,8290],{"class":1133},[1120,10185,10186],{"class":1141},"JSON",[1120,10188,1145],{"class":1133},[1120,10190,10191],{"class":1207},"400",[1120,10193,949],{"class":1133},[1120,10195,9455],{"class":1141},[1120,10197,2167],{"class":1133},[1120,10199,9695],{"class":1141},[1120,10201,7655],{"class":1133},[1120,10203,10204,10207,10209,10212],{"class":1122,"line":2339},[1120,10205,10206],{"class":1866},"            \"error\"",[1120,10208,9703],{"class":1133},[1120,10210,10211],{"class":1141},"translateError",[1120,10213,10214],{"class":1133},"(err),\n",[1120,10216,10217],{"class":1122,"line":2344},[1120,10218,10219],{"class":1133},"        })\n",[1120,10221,10222],{"class":1122,"line":2349},[1120,10223,10224],{"class":1137},"        return\n",[1120,10226,10227],{"class":1122,"line":2355},[1120,10228,5381],{"class":1133},[1120,10230,10231],{"class":1122,"line":2372},[1120,10232,2811],{"class":1133},[1120,10234,10235],{"class":1122,"line":2391},[1120,10236,10237],{"class":1126},"    \u002F\u002F 业务逻辑...\n",[1120,10239,10240],{"class":1122,"line":2402},[1120,10241,1404],{"class":1133},[895,10243],{},[898,10245,10247],{"id":10246},"十系统设计与架构","十、系统设计与架构",[903,10249,10251],{"id":10250},"q74-如何设计一个高并发系统","Q74: 如何设计一个高并发系统",[892,10253,10254],{},[1042,10255,10256],{},"核心策略：",[908,10258,10259,10268],{},[911,10260,10261],{},[914,10262,10263,10266],{},[917,10264,10265],{"align":919},"策略",[917,10267,5027],{"align":919},[925,10269,10270,10280,10290,10300,10310,10319],{},[914,10271,10272,10277],{},[930,10273,10274],{"align":919},[1042,10275,10276],{},"缓存",[930,10278,10279],{"align":919},"多级缓存（本地 + Redis）",[914,10281,10282,10287],{},[930,10283,10284],{"align":919},[1042,10285,10286],{},"异步",[930,10288,10289],{"align":919},"消息队列解耦",[914,10291,10292,10297],{},[930,10293,10294],{"align":919},[1042,10295,10296],{},"限流",[930,10298,10299],{"align":919},"保护系统不被打垮",[914,10301,10302,10307],{},[930,10303,10304],{"align":919},[1042,10305,10306],{},"分库分表",[930,10308,10309],{"align":919},"数据库水平扩展",[914,10311,10312,10316],{},[930,10313,10314],{"align":919},[1042,10315,3999],{},[930,10317,10318],{"align":919},"主写从读",[914,10320,10321,10326],{},[930,10322,10323],{"align":919},[1042,10324,10325],{},"负载均衡",[930,10327,10328],{"align":919},"多实例分担压力",[895,10330],{},[903,10332,10334],{"id":10333},"q75-限流算法有哪些","Q75: 限流算法有哪些",[908,10336,10337,10349],{},[911,10338,10339],{},[914,10340,10341,10344,10347],{},[917,10342,10343],{"align":919},"算法",[917,10345,10346],{"align":919},"特点",[917,10348,5024],{"align":919},[925,10350,10351,10364,10377,10390],{},[914,10352,10353,10358,10361],{},[930,10354,10355],{"align":919},[1042,10356,10357],{},"计数器",[930,10359,10360],{"align":919},"简单，有临界问题",[930,10362,10363],{"align":919},"简单限流",[914,10365,10366,10371,10374],{},[930,10367,10368],{"align":919},[1042,10369,10370],{},"滑动窗口",[930,10372,10373],{"align":919},"解决临界问题",[930,10375,10376],{"align":919},"精确限流",[914,10378,10379,10384,10387],{},[930,10380,10381],{"align":919},[1042,10382,10383],{},"令牌桶",[930,10385,10386],{"align":919},"允许突发流量",[930,10388,10389],{"align":919},"API 限流",[914,10391,10392,10397,10400],{},[930,10393,10394],{"align":919},[1042,10395,10396],{},"漏桶",[930,10398,10399],{"align":919},"平滑流量",[930,10401,10402],{"align":919},"流量整形",[892,10404,10405],{},[1042,10406,10407],{},"令牌桶实现：",[1112,10409,10411],{"className":1114,"code":10410,"language":1116,"meta":11,"style":11},"import \"golang.org\u002Fx\u002Ftime\u002Frate\"\n\nlimiter := rate.NewLimiter(100, 10)  \u002F\u002F 每秒 100 个，突发 10 个\n\nif !limiter.Allow() {\n    c.JSON(429, gin.H{\"error\": \"请求过于频繁\"})\n    return\n}\n",[936,10412,10413,10424,10428,10454,10458,10473,10503,10508],{"__ignoreMap":11},[1120,10414,10415,10417,10419,10422],{"class":1122,"line":1123},[1120,10416,5827],{"class":1137},[1120,10418,8812],{"class":1866},[1120,10420,10421],{"class":1141},"golang.org\u002Fx\u002Ftime\u002Frate",[1120,10423,5838],{"class":1866},[1120,10425,10426],{"class":1122,"line":1130},[1120,10427,1181],{"emptyLinePlaceholder":1180},[1120,10429,10430,10433,10435,10438,10441,10443,10445,10447,10449,10451],{"class":1122,"line":1156},[1120,10431,10432],{"class":1133},"limiter ",[1120,10434,1138],{"class":1137},[1120,10436,10437],{"class":1133}," rate.",[1120,10439,10440],{"class":1141},"NewLimiter",[1120,10442,1145],{"class":1133},[1120,10444,2675],{"class":1207},[1120,10446,949],{"class":1133},[1120,10448,1213],{"class":1207},[1120,10450,2114],{"class":1133},[1120,10452,10453],{"class":1126},"\u002F\u002F 每秒 100 个，突发 10 个\n",[1120,10455,10456],{"class":1122,"line":1177},[1120,10457,1181],{"emptyLinePlaceholder":1180},[1120,10459,10460,10462,10465,10468,10471],{"class":1122,"line":1184},[1120,10461,2238],{"class":1137},[1120,10463,10464],{"class":1137}," !",[1120,10466,10467],{"class":1133},"limiter.",[1120,10469,10470],{"class":1141},"Allow",[1120,10472,2729],{"class":1133},[1120,10474,10475,10477,10479,10481,10484,10486,10488,10490,10492,10494,10496,10498,10501],{"class":1122,"line":1190},[1120,10476,9992],{"class":1133},[1120,10478,10186],{"class":1141},[1120,10480,1145],{"class":1133},[1120,10482,10483],{"class":1207},"429",[1120,10485,949],{"class":1133},[1120,10487,9455],{"class":1141},[1120,10489,2167],{"class":1133},[1120,10491,9695],{"class":1141},[1120,10493,1863],{"class":1133},[1120,10495,9700],{"class":1866},[1120,10497,9703],{"class":1133},[1120,10499,10500],{"class":1866},"\"请求过于频繁\"",[1120,10502,8958],{"class":1133},[1120,10504,10505],{"class":1122,"line":1221},[1120,10506,10507],{"class":1137},"    return\n",[1120,10509,10510],{"class":1122,"line":1251},[1120,10511,1404],{"class":1133},[895,10513],{},[903,10515,10517],{"id":10516},"q76-如何实现服务降级","Q76: 如何实现服务降级",[892,10519,10520],{},[1042,10521,10522],{},"降级策略：",[1112,10524,10526],{"className":1114,"code":10525,"language":1116,"meta":11,"style":11},"func GetUserInfo(userID string) (*User, error) {\n    \u002F\u002F 1. 尝试从缓存获取\n    if user, err := cache.Get(userID); err == nil {\n        return user, nil\n    }\n    \n    \u002F\u002F 2. 熔断器检查\n    if circuitBreaker.IsOpen() {\n        \u002F\u002F 降级：返回默认数据\n        return getDefaultUser(userID), nil\n    }\n    \n    \u002F\u002F 3. 调用服务\n    user, err := userService.Get(userID)\n    if err != nil {\n        circuitBreaker.RecordFailure()\n        \u002F\u002F 降级：返回缓存的旧数据\n        return cache.GetStale(userID), nil\n    }\n    \n    return user, nil\n}\n",[936,10527,10528,10555,10560,10583,10593,10597,10601,10606,10618,10623,10635,10639,10643,10648,10663,10675,10685,10690,10703,10707,10711,10719],{"__ignoreMap":11},[1120,10529,10530,10532,10535,10537,10540,10542,10545,10547,10549,10551,10553],{"class":1122,"line":1123},[1120,10531,1440],{"class":1137},[1120,10533,10534],{"class":1141}," GetUserInfo",[1120,10536,1145],{"class":1133},[1120,10538,10539],{"class":1515},"userID",[1120,10541,8559],{"class":1137},[1120,10543,10544],{"class":1133},") (",[1120,10546,1380],{"class":1137},[1120,10548,1989],{"class":1141},[1120,10550,949],{"class":1133},[1120,10552,2857],{"class":1137},[1120,10554,1521],{"class":1133},[1120,10556,10557],{"class":1122,"line":1130},[1120,10558,10559],{"class":1126},"    \u002F\u002F 1. 尝试从缓存获取\n",[1120,10561,10562,10564,10567,10569,10572,10574,10577,10579,10581],{"class":1122,"line":1156},[1120,10563,5352],{"class":1137},[1120,10565,10566],{"class":1133}," user, err ",[1120,10568,1138],{"class":1137},[1120,10570,10571],{"class":1133}," cache.",[1120,10573,7714],{"class":1141},[1120,10575,10576],{"class":1133},"(userID); err ",[1120,10578,1907],{"class":1137},[1120,10580,2111],{"class":1207},[1120,10582,1334],{"class":1133},[1120,10584,10585,10587,10590],{"class":1122,"line":1177},[1120,10586,7674],{"class":1137},[1120,10588,10589],{"class":1133}," user, ",[1120,10591,10592],{"class":1207},"nil\n",[1120,10594,10595],{"class":1122,"line":1184},[1120,10596,5381],{"class":1133},[1120,10598,10599],{"class":1122,"line":1190},[1120,10600,2811],{"class":1133},[1120,10602,10603],{"class":1122,"line":1221},[1120,10604,10605],{"class":1126},"    \u002F\u002F 2. 熔断器检查\n",[1120,10607,10608,10610,10613,10616],{"class":1122,"line":1251},[1120,10609,5352],{"class":1137},[1120,10611,10612],{"class":1133}," circuitBreaker.",[1120,10614,10615],{"class":1141},"IsOpen",[1120,10617,2729],{"class":1133},[1120,10619,10620],{"class":1122,"line":1504},[1120,10621,10622],{"class":1126},"        \u002F\u002F 降级：返回默认数据\n",[1120,10624,10625,10627,10630,10633],{"class":1122,"line":1524},[1120,10626,7674],{"class":1137},[1120,10628,10629],{"class":1141}," getDefaultUser",[1120,10631,10632],{"class":1133},"(userID), ",[1120,10634,10592],{"class":1207},[1120,10636,10637],{"class":1122,"line":1537},[1120,10638,5381],{"class":1133},[1120,10640,10641],{"class":1122,"line":1548},[1120,10642,2811],{"class":1133},[1120,10644,10645],{"class":1122,"line":2333},[1120,10646,10647],{"class":1126},"    \u002F\u002F 3. 调用服务\n",[1120,10649,10650,10653,10655,10658,10660],{"class":1122,"line":2339},[1120,10651,10652],{"class":1133},"    user, err ",[1120,10654,1138],{"class":1137},[1120,10656,10657],{"class":1133}," userService.",[1120,10659,7714],{"class":1141},[1120,10661,10662],{"class":1133},"(userID)\n",[1120,10664,10665,10667,10669,10671,10673],{"class":1122,"line":2344},[1120,10666,5352],{"class":1137},[1120,10668,2241],{"class":1133},[1120,10670,2244],{"class":1137},[1120,10672,2111],{"class":1207},[1120,10674,1334],{"class":1133},[1120,10676,10677,10680,10683],{"class":1122,"line":2349},[1120,10678,10679],{"class":1133},"        circuitBreaker.",[1120,10681,10682],{"class":1141},"RecordFailure",[1120,10684,2796],{"class":1133},[1120,10686,10687],{"class":1122,"line":2355},[1120,10688,10689],{"class":1126},"        \u002F\u002F 降级：返回缓存的旧数据\n",[1120,10691,10692,10694,10696,10699,10701],{"class":1122,"line":2372},[1120,10693,7674],{"class":1137},[1120,10695,10571],{"class":1133},[1120,10697,10698],{"class":1141},"GetStale",[1120,10700,10632],{"class":1133},[1120,10702,10592],{"class":1207},[1120,10704,10705],{"class":1122,"line":2391},[1120,10706,5381],{"class":1133},[1120,10708,10709],{"class":1122,"line":2402},[1120,10710,2811],{"class":1133},[1120,10712,10713,10715,10717],{"class":1122,"line":3100},[1120,10714,1482],{"class":1137},[1120,10716,10589],{"class":1133},[1120,10718,10592],{"class":1207},[1120,10720,10721],{"class":1122,"line":3106},[1120,10722,1404],{"class":1133},[895,10724],{},[903,10726,10728],{"id":10727},"q77-什么是高可用如何实现","Q77: 什么是高可用，如何实现",[892,10730,10731],{},[1042,10732,10733],{},"高可用 = 系统持续提供服务的能力",[908,10735,10736,10746],{},[911,10737,10738],{},[914,10739,10740,10743],{},[917,10741,10742],{"align":919},"层面",[917,10744,10745],{"align":919},"方案",[925,10747,10748,10758,10768,10778],{},[914,10749,10750,10755],{},[930,10751,10752],{"align":919},[1042,10753,10754],{},"应用层",[930,10756,10757],{"align":919},"多实例部署、无状态服务",[914,10759,10760,10765],{},[930,10761,10762],{"align":919},[1042,10763,10764],{},"网络层",[930,10766,10767],{"align":919},"负载均衡、多机房",[914,10769,10770,10775],{},[930,10771,10772],{"align":919},[1042,10773,10774],{},"数据层",[930,10776,10777],{"align":919},"主从复制、读写分离",[914,10779,10780,10785],{},[930,10781,10782],{"align":919},[1042,10783,10784],{},"容灾",[930,10786,10787],{"align":919},"故障转移、熔断降级",[892,10789,10790],{},[1042,10791,10792],{},"健康检查：",[1112,10794,10796],{"className":1114,"code":10795,"language":1116,"meta":11,"style":11},"func healthCheck(c *gin.Context) {\n    \u002F\u002F 检查依赖服务\n    if err := db.Ping(); err != nil {\n        c.JSON(503, gin.H{\"status\": \"unhealthy\"})\n        return\n    }\n    if err := redis.Ping(); err != nil {\n        c.JSON(503, gin.H{\"status\": \"unhealthy\"})\n        return\n    }\n    c.JSON(200, gin.H{\"status\": \"healthy\"})\n}\n",[936,10797,10798,10819,10824,10847,10878,10882,10886,10906,10934,10938,10942,10971],{"__ignoreMap":11},[1120,10799,10800,10802,10805,10807,10809,10811,10813,10815,10817],{"class":1122,"line":1123},[1120,10801,1440],{"class":1137},[1120,10803,10804],{"class":1141}," healthCheck",[1120,10806,1145],{"class":1133},[1120,10808,8298],{"class":1515},[1120,10810,6355],{"class":1137},[1120,10812,9455],{"class":1141},[1120,10814,2167],{"class":1133},[1120,10816,6058],{"class":1141},[1120,10818,1521],{"class":1133},[1120,10820,10821],{"class":1122,"line":1130},[1120,10822,10823],{"class":1126},"    \u002F\u002F 检查依赖服务\n",[1120,10825,10826,10828,10830,10832,10835,10838,10841,10843,10845],{"class":1122,"line":1156},[1120,10827,5352],{"class":1137},[1120,10829,2241],{"class":1133},[1120,10831,1138],{"class":1137},[1120,10833,10834],{"class":1133}," db.",[1120,10836,10837],{"class":1141},"Ping",[1120,10839,10840],{"class":1133},"(); err ",[1120,10842,2244],{"class":1137},[1120,10844,2111],{"class":1207},[1120,10846,1334],{"class":1133},[1120,10848,10849,10851,10853,10855,10858,10860,10862,10864,10866,10868,10871,10873,10876],{"class":1122,"line":1177},[1120,10850,8290],{"class":1133},[1120,10852,10186],{"class":1141},[1120,10854,1145],{"class":1133},[1120,10856,10857],{"class":1207},"503",[1120,10859,949],{"class":1133},[1120,10861,9455],{"class":1141},[1120,10863,2167],{"class":1133},[1120,10865,9695],{"class":1141},[1120,10867,1863],{"class":1133},[1120,10869,10870],{"class":1866},"\"status\"",[1120,10872,9703],{"class":1133},[1120,10874,10875],{"class":1866},"\"unhealthy\"",[1120,10877,8958],{"class":1133},[1120,10879,10880],{"class":1122,"line":1184},[1120,10881,10224],{"class":1137},[1120,10883,10884],{"class":1122,"line":1190},[1120,10885,5381],{"class":1133},[1120,10887,10888,10890,10892,10894,10896,10898,10900,10902,10904],{"class":1122,"line":1221},[1120,10889,5352],{"class":1137},[1120,10891,2241],{"class":1133},[1120,10893,1138],{"class":1137},[1120,10895,8662],{"class":1133},[1120,10897,10837],{"class":1141},[1120,10899,10840],{"class":1133},[1120,10901,2244],{"class":1137},[1120,10903,2111],{"class":1207},[1120,10905,1334],{"class":1133},[1120,10907,10908,10910,10912,10914,10916,10918,10920,10922,10924,10926,10928,10930,10932],{"class":1122,"line":1251},[1120,10909,8290],{"class":1133},[1120,10911,10186],{"class":1141},[1120,10913,1145],{"class":1133},[1120,10915,10857],{"class":1207},[1120,10917,949],{"class":1133},[1120,10919,9455],{"class":1141},[1120,10921,2167],{"class":1133},[1120,10923,9695],{"class":1141},[1120,10925,1863],{"class":1133},[1120,10927,10870],{"class":1866},[1120,10929,9703],{"class":1133},[1120,10931,10875],{"class":1866},[1120,10933,8958],{"class":1133},[1120,10935,10936],{"class":1122,"line":1504},[1120,10937,10224],{"class":1137},[1120,10939,10940],{"class":1122,"line":1524},[1120,10941,5381],{"class":1133},[1120,10943,10944,10946,10948,10950,10952,10954,10956,10958,10960,10962,10964,10966,10969],{"class":1122,"line":1537},[1120,10945,9992],{"class":1133},[1120,10947,10186],{"class":1141},[1120,10949,1145],{"class":1133},[1120,10951,7417],{"class":1207},[1120,10953,949],{"class":1133},[1120,10955,9455],{"class":1141},[1120,10957,2167],{"class":1133},[1120,10959,9695],{"class":1141},[1120,10961,1863],{"class":1133},[1120,10963,10870],{"class":1866},[1120,10965,9703],{"class":1133},[1120,10967,10968],{"class":1866},"\"healthy\"",[1120,10970,8958],{"class":1133},[1120,10972,10973],{"class":1122,"line":1548},[1120,10974,1404],{"class":1133},[895,10976],{},[898,10978,10980],{"id":10979},"十一性能调优","十一、性能调优",[903,10982,10984],{"id":10983},"q78-pprof-怎么用","Q78: pprof 怎么用",[892,10986,10987],{},[1042,10988,10989],{},"启用 pprof：",[1112,10991,10993],{"className":1114,"code":10992,"language":1116,"meta":11,"style":11},"import _ \"net\u002Fhttp\u002Fpprof\"\n\ngo func() {\n    http.ListenAndServe(\":6060\", nil)\n}()\n",[936,10994,10995,11007,11011,11019,11036],{"__ignoreMap":11},[1120,10996,10997,10999,11001,11003,11005],{"class":1122,"line":1123},[1120,10998,5827],{"class":1137},[1120,11000,5830],{"class":1133},[1120,11002,2301],{"class":1866},[1120,11004,5835],{"class":1141},[1120,11006,5838],{"class":1866},[1120,11008,11009],{"class":1122,"line":1130},[1120,11010,1181],{"emptyLinePlaceholder":1180},[1120,11012,11013,11015,11017],{"class":1122,"line":1156},[1120,11014,1116],{"class":1137},[1120,11016,1468],{"class":1137},[1120,11018,2729],{"class":1133},[1120,11020,11021,11024,11026,11028,11030,11032,11034],{"class":1122,"line":1177},[1120,11022,11023],{"class":1133},"    http.",[1120,11025,5848],{"class":1141},[1120,11027,1145],{"class":1133},[1120,11029,5853],{"class":1866},[1120,11031,949],{"class":1133},[1120,11033,2686],{"class":1207},[1120,11035,2591],{"class":1133},[1120,11037,11038],{"class":1122,"line":1184},[1120,11039,4799],{"class":1133},[892,11041,11042],{},[1042,11043,11044],{},"常用分析：",[1112,11046,11048],{"className":5404,"code":11047,"language":5406,"meta":11,"style":11},"# CPU 分析\ngo tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fprofile?seconds=30\n\n# 内存分析\ngo tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap\n\n# Goroutine 分析\ngo tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fgoroutine\n\n# 阻塞分析\ngo tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fblock\n\n# 常用命令\n(pprof) top         # 热点函数\n(pprof) list func   # 查看函数代码\n(pprof) web         # 生成图形\n",[936,11049,11050,11054,11066,11070,11074,11084,11088,11092,11102,11106,11111,11122,11126,11130,11145,11161],{"__ignoreMap":11},[1120,11051,11052],{"class":1122,"line":1123},[1120,11053,8099],{"class":1126},[1120,11055,11056,11058,11060,11062,11064],{"class":1122,"line":1130},[1120,11057,1116],{"class":1141},[1120,11059,8106],{"class":1866},[1120,11061,8109],{"class":1866},[1120,11063,8112],{"class":1866},[1120,11065,8115],{"class":1207},[1120,11067,11068],{"class":1122,"line":1156},[1120,11069,1181],{"emptyLinePlaceholder":1180},[1120,11071,11072],{"class":1122,"line":1177},[1120,11073,8124],{"class":1126},[1120,11075,11076,11078,11080,11082],{"class":1122,"line":1184},[1120,11077,1116],{"class":1141},[1120,11079,8106],{"class":1866},[1120,11081,8109],{"class":1866},[1120,11083,8135],{"class":1866},[1120,11085,11086],{"class":1122,"line":1190},[1120,11087,1181],{"emptyLinePlaceholder":1180},[1120,11089,11090],{"class":1122,"line":1221},[1120,11091,8144],{"class":1126},[1120,11093,11094,11096,11098,11100],{"class":1122,"line":1251},[1120,11095,1116],{"class":1141},[1120,11097,8106],{"class":1866},[1120,11099,8109],{"class":1866},[1120,11101,8155],{"class":1866},[1120,11103,11104],{"class":1122,"line":1504},[1120,11105,1181],{"emptyLinePlaceholder":1180},[1120,11107,11108],{"class":1122,"line":1524},[1120,11109,11110],{"class":1126},"# 阻塞分析\n",[1120,11112,11113,11115,11117,11119],{"class":1122,"line":1537},[1120,11114,1116],{"class":1141},[1120,11116,8106],{"class":1866},[1120,11118,8109],{"class":1866},[1120,11120,11121],{"class":1866}," http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fblock\n",[1120,11123,11124],{"class":1122,"line":1548},[1120,11125,1181],{"emptyLinePlaceholder":1180},[1120,11127,11128],{"class":1122,"line":2333},[1120,11129,8164],{"class":1126},[1120,11131,11132,11134,11137,11139,11142],{"class":1122,"line":2339},[1120,11133,1145],{"class":1133},[1120,11135,11136],{"class":1141},"pprof",[1120,11138,2519],{"class":1133},[1120,11140,11141],{"class":1141},"top",[1120,11143,11144],{"class":1126},"         # 热点函数\n",[1120,11146,11147,11149,11151,11153,11156,11158],{"class":1122,"line":2344},[1120,11148,1145],{"class":1133},[1120,11150,11136],{"class":1141},[1120,11152,2519],{"class":1133},[1120,11154,11155],{"class":1141},"list",[1120,11157,1468],{"class":1866},[1120,11159,11160],{"class":1126},"   # 查看函数代码\n",[1120,11162,11163,11165,11167,11169,11172],{"class":1122,"line":2349},[1120,11164,1145],{"class":1133},[1120,11166,11136],{"class":1141},[1120,11168,2519],{"class":1133},[1120,11170,11171],{"class":1141},"web",[1120,11173,11174],{"class":1126},"         # 生成图形\n",[895,11176],{},[903,11178,11180],{"id":11179},"q79-cpu-飙高如何排查","Q79: CPU 飙高如何排查",[1112,11182,11184],{"className":5404,"code":11183,"language":5406,"meta":11,"style":11},"# 1. 找到 Go 进程\nps aux | grep myapp\n\n# 2. 采集 CPU Profile\ncurl http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fprofile?seconds=30 > cpu.pprof\n\n# 3. 分析\ngo tool pprof cpu.pprof\n(pprof) top 20\n(pprof) web\n",[936,11185,11186,11191,11208,11212,11217,11232,11236,11241,11251,11264],{"__ignoreMap":11},[1120,11187,11188],{"class":1122,"line":1123},[1120,11189,11190],{"class":1126},"# 1. 找到 Go 进程\n",[1120,11192,11193,11196,11199,11202,11205],{"class":1122,"line":1130},[1120,11194,11195],{"class":1141},"ps",[1120,11197,11198],{"class":1866}," aux",[1120,11200,11201],{"class":1137}," |",[1120,11203,11204],{"class":1141}," grep",[1120,11206,11207],{"class":1866}," myapp\n",[1120,11209,11210],{"class":1122,"line":1156},[1120,11211,1181],{"emptyLinePlaceholder":1180},[1120,11213,11214],{"class":1122,"line":1177},[1120,11215,11216],{"class":1126},"# 2. 采集 CPU Profile\n",[1120,11218,11219,11222,11224,11226,11229],{"class":1122,"line":1184},[1120,11220,11221],{"class":1141},"curl",[1120,11223,8112],{"class":1866},[1120,11225,8875],{"class":1207},[1120,11227,11228],{"class":1137}," >",[1120,11230,11231],{"class":1866}," cpu.pprof\n",[1120,11233,11234],{"class":1122,"line":1190},[1120,11235,1181],{"emptyLinePlaceholder":1180},[1120,11237,11238],{"class":1122,"line":1221},[1120,11239,11240],{"class":1126},"# 3. 分析\n",[1120,11242,11243,11245,11247,11249],{"class":1122,"line":1251},[1120,11244,1116],{"class":1141},[1120,11246,8106],{"class":1866},[1120,11248,8109],{"class":1866},[1120,11250,11231],{"class":1866},[1120,11252,11253,11255,11257,11259,11261],{"class":1122,"line":1504},[1120,11254,1145],{"class":1133},[1120,11256,11136],{"class":1141},[1120,11258,2519],{"class":1133},[1120,11260,11141],{"class":1141},[1120,11262,11263],{"class":1207}," 20\n",[1120,11265,11266,11268,11270,11272],{"class":1122,"line":1524},[1120,11267,1145],{"class":1133},[1120,11269,11136],{"class":1141},[1120,11271,2519],{"class":1133},[1120,11273,11274],{"class":1141},"web\n",[892,11276,11277],{},[1042,11278,11279],{},"常见原因：",[1667,11281,11282,11285,11288,11291],{},[1293,11283,11284],{},"死循环",[1293,11286,11287],{},"频繁 GC",[1293,11289,11290],{},"锁竞争",[1293,11292,11293],{},"正则表达式",[895,11295],{},[903,11297,11299],{"id":11298},"q80-内存暴涨如何排查","Q80: 内存暴涨如何排查",[1112,11301,11303],{"className":5404,"code":11302,"language":5406,"meta":11,"style":11},"# 采集堆内存\ncurl http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap > heap.pprof\n\n# 分析\ngo tool pprof heap.pprof\n(pprof) top -inuse_space    # 当前使用\n(pprof) top -alloc_space    # 累计分配\n",[936,11304,11305,11310,11322,11326,11331,11341,11357],{"__ignoreMap":11},[1120,11306,11307],{"class":1122,"line":1123},[1120,11308,11309],{"class":1126},"# 采集堆内存\n",[1120,11311,11312,11314,11317,11319],{"class":1122,"line":1130},[1120,11313,11221],{"class":1141},[1120,11315,11316],{"class":1866}," http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap",[1120,11318,11228],{"class":1137},[1120,11320,11321],{"class":1866}," heap.pprof\n",[1120,11323,11324],{"class":1122,"line":1156},[1120,11325,1181],{"emptyLinePlaceholder":1180},[1120,11327,11328],{"class":1122,"line":1177},[1120,11329,11330],{"class":1126},"# 分析\n",[1120,11332,11333,11335,11337,11339],{"class":1122,"line":1184},[1120,11334,1116],{"class":1141},[1120,11336,8106],{"class":1866},[1120,11338,8109],{"class":1866},[1120,11340,11321],{"class":1866},[1120,11342,11343,11345,11347,11349,11351,11354],{"class":1122,"line":1190},[1120,11344,1145],{"class":1133},[1120,11346,11136],{"class":1141},[1120,11348,2519],{"class":1133},[1120,11350,11141],{"class":1141},[1120,11352,11353],{"class":1207}," -inuse_space",[1120,11355,11356],{"class":1126},"    # 当前使用\n",[1120,11358,11359,11361,11363,11365,11367,11370],{"class":1122,"line":1221},[1120,11360,1145],{"class":1133},[1120,11362,11136],{"class":1141},[1120,11364,2519],{"class":1133},[1120,11366,11141],{"class":1141},[1120,11368,11369],{"class":1207}," -alloc_space",[1120,11371,11372],{"class":1126},"    # 累计分配\n",[892,11374,11375],{},[1042,11376,11279],{},[1667,11378,11379,11382,11385,11388],{},[1293,11380,11381],{},"Goroutine 泄漏",[1293,11383,11384],{},"缓存无限增长",[1293,11386,11387],{},"大对象未释放",[1293,11389,11390],{},"切片底层数组未释放",[895,11392],{},[903,11394,11396],{"id":11395},"q81-火焰图怎么看","Q81: 火焰图怎么看",[892,11398,11399],{},[1042,11400,11401],{},"生成火焰图：",[1112,11403,11405],{"className":5404,"code":11404,"language":5406,"meta":11,"style":11},"go tool pprof -http=:8080 cpu.pprof\n",[936,11406,11407],{"__ignoreMap":11},[1120,11408,11409,11411,11413,11415,11418],{"class":1122,"line":1123},[1120,11410,1116],{"class":1141},[1120,11412,8106],{"class":1866},[1120,11414,8109],{"class":1866},[1120,11416,11417],{"class":1207}," -http=:8080",[1120,11419,11231],{"class":1866},[892,11421,11422],{},[1042,11423,11424],{},"解读：",[1667,11426,11427,11433,11439],{},[1293,11428,11429,11432],{},[1042,11430,11431],{},"横轴","：占用比例（越宽越耗资源）",[1293,11434,11435,11438],{},[1042,11436,11437],{},"纵轴","：调用栈深度",[1293,11440,11441,11444],{},[1042,11442,11443],{},"颜色","：无特殊含义，仅区分",[892,11446,11447,11450],{},[1042,11448,11449],{},"优化目标："," 找到最宽的\"平台\"（热点函数）",[895,11452],{},[903,11454,11456],{"id":11455},"q82-如何优化-json-序列化","Q82: 如何优化 JSON 序列化",[908,11458,11459,11468],{},[911,11460,11461],{},[914,11462,11463,11466],{},[917,11464,11465],{"align":919},"库",[917,11467,10346],{"align":919},[925,11469,11470,11477,11485,11493],{},[914,11471,11472,11474],{},[930,11473,236],{"align":919},[930,11475,11476],{"align":919},"标准库，通用",[914,11478,11479,11482],{},[930,11480,11481],{"align":919},"jsoniter",[930,11483,11484],{"align":919},"兼容标准库，更快",[914,11486,11487,11490],{},[930,11488,11489],{"align":919},"sonic",[930,11491,11492],{"align":919},"字节跳动，SIMD 加速",[914,11494,11495,11498],{},[930,11496,11497],{"align":919},"easyjson",[930,11499,11500],{"align":919},"代码生成，零反射",[1112,11502,11504],{"className":1114,"code":11503,"language":1116,"meta":11,"style":11},"import jsoniter \"github.com\u002Fjson-iterator\u002Fgo\"\n\nvar json = jsoniter.ConfigCompatibleWithStandardLibrary\njson.Marshal(obj)\njson.Unmarshal(data, &obj)\n",[936,11505,11506,11520,11524,11536,11547],{"__ignoreMap":11},[1120,11507,11508,11510,11513,11515,11518],{"class":1122,"line":1123},[1120,11509,5827],{"class":1137},[1120,11511,11512],{"class":1133}," jsoniter ",[1120,11514,2301],{"class":1866},[1120,11516,11517],{"class":1141},"github.com\u002Fjson-iterator\u002Fgo",[1120,11519,5838],{"class":1866},[1120,11521,11522],{"class":1122,"line":1130},[1120,11523,1181],{"emptyLinePlaceholder":1180},[1120,11525,11526,11528,11531,11533],{"class":1122,"line":1156},[1120,11527,2066],{"class":1137},[1120,11529,11530],{"class":1133}," json ",[1120,11532,2094],{"class":1137},[1120,11534,11535],{"class":1133}," jsoniter.ConfigCompatibleWithStandardLibrary\n",[1120,11537,11538,11541,11544],{"class":1122,"line":1177},[1120,11539,11540],{"class":1133},"json.",[1120,11542,11543],{"class":1141},"Marshal",[1120,11545,11546],{"class":1133},"(obj)\n",[1120,11548,11549,11551,11554,11557,11559],{"class":1122,"line":1184},[1120,11550,11540],{"class":1133},[1120,11552,11553],{"class":1141},"Unmarshal",[1120,11555,11556],{"class":1133},"(data, ",[1120,11558,2385],{"class":1137},[1120,11560,11561],{"class":1133},"obj)\n",[895,11563],{},[898,11565,11567],{"id":11566},"十二云原生部署","十二、云原生部署",[903,11569,11571],{"id":11570},"q83-go-服务-docker-镜像怎么做","Q83: Go 服务 Docker 镜像怎么做",[892,11573,11574],{},[1042,11575,11576],{},"多阶段构建：",[1112,11578,11582],{"className":11579,"code":11580,"language":11581,"meta":11,"style":11},"language-dockerfile shiki shiki-themes github-light github-light github-dark","# 构建阶段\nFROM golang:1.21-alpine AS builder\nWORKDIR \u002Fapp\nCOPY go.mod go.sum .\u002F\nRUN go mod download\nCOPY . .\nRUN CGO_ENABLED=0 go build -o main .\n\n# 运行阶段\nFROM alpine:latest\nRUN apk --no-cache add ca-certificates\nWORKDIR \u002Fapp\nCOPY --from=builder \u002Fapp\u002Fmain .\nEXPOSE 8080\nCMD [\".\u002Fmain\"]\n","dockerfile",[936,11583,11584,11589,11603,11611,11619,11627,11634,11641,11645,11650,11657,11664,11670,11677,11685],{"__ignoreMap":11},[1120,11585,11586],{"class":1122,"line":1123},[1120,11587,11588],{"class":1126},"# 构建阶段\n",[1120,11590,11591,11594,11597,11600],{"class":1122,"line":1130},[1120,11592,11593],{"class":1137},"FROM",[1120,11595,11596],{"class":1133}," golang:1.21-alpine ",[1120,11598,11599],{"class":1137},"AS",[1120,11601,11602],{"class":1133}," builder\n",[1120,11604,11605,11608],{"class":1122,"line":1156},[1120,11606,11607],{"class":1137},"WORKDIR",[1120,11609,11610],{"class":1133}," \u002Fapp\n",[1120,11612,11613,11616],{"class":1122,"line":1177},[1120,11614,11615],{"class":1137},"COPY",[1120,11617,11618],{"class":1133}," go.mod go.sum .\u002F\n",[1120,11620,11621,11624],{"class":1122,"line":1184},[1120,11622,11623],{"class":1137},"RUN",[1120,11625,11626],{"class":1133}," go mod download\n",[1120,11628,11629,11631],{"class":1122,"line":1190},[1120,11630,11615],{"class":1137},[1120,11632,11633],{"class":1133}," . .\n",[1120,11635,11636,11638],{"class":1122,"line":1221},[1120,11637,11623],{"class":1137},[1120,11639,11640],{"class":1133}," CGO_ENABLED=0 go build -o main .\n",[1120,11642,11643],{"class":1122,"line":1251},[1120,11644,1181],{"emptyLinePlaceholder":1180},[1120,11646,11647],{"class":1122,"line":1504},[1120,11648,11649],{"class":1126},"# 运行阶段\n",[1120,11651,11652,11654],{"class":1122,"line":1524},[1120,11653,11593],{"class":1137},[1120,11655,11656],{"class":1133}," alpine:latest\n",[1120,11658,11659,11661],{"class":1122,"line":1537},[1120,11660,11623],{"class":1137},[1120,11662,11663],{"class":1133}," apk --no-cache add ca-certificates\n",[1120,11665,11666,11668],{"class":1122,"line":1548},[1120,11667,11607],{"class":1137},[1120,11669,11610],{"class":1133},[1120,11671,11672,11674],{"class":1122,"line":2333},[1120,11673,11615],{"class":1137},[1120,11675,11676],{"class":1133}," --from=builder \u002Fapp\u002Fmain .\n",[1120,11678,11679,11682],{"class":1122,"line":2339},[1120,11680,11681],{"class":1137},"EXPOSE",[1120,11683,11684],{"class":1133}," 8080\n",[1120,11686,11687,11690,11693,11696],{"class":1122,"line":2344},[1120,11688,11689],{"class":1137},"CMD",[1120,11691,11692],{"class":1133}," [",[1120,11694,11695],{"class":1866},"\".\u002Fmain\"",[1120,11697,11698],{"class":1133},"]\n",[892,11700,11701],{},[1042,11702,11703],{},"最终镜像约 10-20MB",[895,11705],{},[903,11707,11709],{"id":11708},"q84-k8s-基本组件","Q84: K8s 基本组件",[908,11711,11712,11720],{},[911,11713,11714],{},[914,11715,11716,11718],{},[917,11717,6848],{"align":919},[917,11719,5027],{"align":919},[925,11721,11722,11732,11742,11752,11762,11772],{},[914,11723,11724,11729],{},[930,11725,11726],{"align":919},[1042,11727,11728],{},"Pod",[930,11730,11731],{"align":919},"最小部署单元",[914,11733,11734,11739],{},[930,11735,11736],{"align":919},[1042,11737,11738],{},"Deployment",[930,11740,11741],{"align":919},"管理 Pod 副本",[914,11743,11744,11749],{},[930,11745,11746],{"align":919},[1042,11747,11748],{},"Service",[930,11750,11751],{"align":919},"服务发现和负载均衡",[914,11753,11754,11759],{},[930,11755,11756],{"align":919},[1042,11757,11758],{},"Ingress",[930,11760,11761],{"align":919},"对外暴露 HTTP 服务",[914,11763,11764,11769],{},[930,11765,11766],{"align":919},[1042,11767,11768],{},"ConfigMap",[930,11770,11771],{"align":919},"配置管理",[914,11773,11774,11779],{},[930,11775,11776],{"align":919},[1042,11777,11778],{},"Secret",[930,11780,11781],{"align":919},"敏感配置",[895,11783],{},[903,11785,11787],{"id":11786},"q85-服务如何在-k8s-中暴露","Q85: 服务如何在 K8s 中暴露",[1112,11789,11793],{"className":11790,"code":11791,"language":11792,"meta":11,"style":11},"language-yaml shiki shiki-themes github-light github-light github-dark","# Service（集群内部）\napiVersion: v1\nkind: Service\nmetadata:\n  name: my-service\nspec:\n  selector:\n    app: myapp\n  ports:\n    - port: 80\n      targetPort: 8080\n---\n# Ingress（对外）\napiVersion: networking.k8s.io\u002Fv1\nkind: Ingress\nmetadata:\n  name: my-ingress\nspec:\n  rules:\n    - host: api.example.com\n      http:\n        paths:\n          - path: \u002F\n            pathType: Prefix\n            backend:\n              service:\n                name: my-service\n                port:\n                  number: 80\n","yaml",[936,11794,11795,11800,11811,11821,11828,11838,11845,11852,11862,11869,11882,11892,11897,11902,11911,11920,11926,11935,11941,11948,11960,11967,11974,11987,11997,12005,12013,12023,12031],{"__ignoreMap":11},[1120,11796,11797],{"class":1122,"line":1123},[1120,11798,11799],{"class":1126},"# Service（集群内部）\n",[1120,11801,11802,11806,11808],{"class":1122,"line":1130},[1120,11803,11805],{"class":11804},"sovSZ","apiVersion",[1120,11807,9703],{"class":1133},[1120,11809,11810],{"class":1866},"v1\n",[1120,11812,11813,11816,11818],{"class":1122,"line":1156},[1120,11814,11815],{"class":11804},"kind",[1120,11817,9703],{"class":1133},[1120,11819,11820],{"class":1866},"Service\n",[1120,11822,11823,11826],{"class":1122,"line":1177},[1120,11824,11825],{"class":11804},"metadata",[1120,11827,1651],{"class":1133},[1120,11829,11830,11833,11835],{"class":1122,"line":1184},[1120,11831,11832],{"class":11804},"  name",[1120,11834,9703],{"class":1133},[1120,11836,11837],{"class":1866},"my-service\n",[1120,11839,11840,11843],{"class":1122,"line":1190},[1120,11841,11842],{"class":11804},"spec",[1120,11844,1651],{"class":1133},[1120,11846,11847,11850],{"class":1122,"line":1221},[1120,11848,11849],{"class":11804},"  selector",[1120,11851,1651],{"class":1133},[1120,11853,11854,11857,11859],{"class":1122,"line":1251},[1120,11855,11856],{"class":11804},"    app",[1120,11858,9703],{"class":1133},[1120,11860,11861],{"class":1866},"myapp\n",[1120,11863,11864,11867],{"class":1122,"line":1504},[1120,11865,11866],{"class":11804},"  ports",[1120,11868,1651],{"class":1133},[1120,11870,11871,11874,11877,11879],{"class":1122,"line":1524},[1120,11872,11873],{"class":1133},"    - ",[1120,11875,11876],{"class":11804},"port",[1120,11878,9703],{"class":1133},[1120,11880,11881],{"class":1207},"80\n",[1120,11883,11884,11887,11889],{"class":1122,"line":1537},[1120,11885,11886],{"class":11804},"      targetPort",[1120,11888,9703],{"class":1133},[1120,11890,11891],{"class":1207},"8080\n",[1120,11893,11894],{"class":1122,"line":1548},[1120,11895,11896],{"class":1141},"---\n",[1120,11898,11899],{"class":1122,"line":2333},[1120,11900,11901],{"class":1126},"# Ingress（对外）\n",[1120,11903,11904,11906,11908],{"class":1122,"line":2339},[1120,11905,11805],{"class":11804},[1120,11907,9703],{"class":1133},[1120,11909,11910],{"class":1866},"networking.k8s.io\u002Fv1\n",[1120,11912,11913,11915,11917],{"class":1122,"line":2344},[1120,11914,11815],{"class":11804},[1120,11916,9703],{"class":1133},[1120,11918,11919],{"class":1866},"Ingress\n",[1120,11921,11922,11924],{"class":1122,"line":2349},[1120,11923,11825],{"class":11804},[1120,11925,1651],{"class":1133},[1120,11927,11928,11930,11932],{"class":1122,"line":2355},[1120,11929,11832],{"class":11804},[1120,11931,9703],{"class":1133},[1120,11933,11934],{"class":1866},"my-ingress\n",[1120,11936,11937,11939],{"class":1122,"line":2372},[1120,11938,11842],{"class":11804},[1120,11940,1651],{"class":1133},[1120,11942,11943,11946],{"class":1122,"line":2391},[1120,11944,11945],{"class":11804},"  rules",[1120,11947,1651],{"class":1133},[1120,11949,11950,11952,11955,11957],{"class":1122,"line":2402},[1120,11951,11873],{"class":1133},[1120,11953,11954],{"class":11804},"host",[1120,11956,9703],{"class":1133},[1120,11958,11959],{"class":1866},"api.example.com\n",[1120,11961,11962,11965],{"class":1122,"line":3100},[1120,11963,11964],{"class":11804},"      http",[1120,11966,1651],{"class":1133},[1120,11968,11969,11972],{"class":1122,"line":3106},[1120,11970,11971],{"class":11804},"        paths",[1120,11973,1651],{"class":1133},[1120,11975,11976,11979,11982,11984],{"class":1122,"line":9843},[1120,11977,11978],{"class":1133},"          - ",[1120,11980,11981],{"class":11804},"path",[1120,11983,9703],{"class":1133},[1120,11985,11986],{"class":1866},"\u002F\n",[1120,11988,11989,11992,11994],{"class":1122,"line":9848},[1120,11990,11991],{"class":11804},"            pathType",[1120,11993,9703],{"class":1133},[1120,11995,11996],{"class":1866},"Prefix\n",[1120,11998,12000,12003],{"class":1122,"line":11999},25,[1120,12001,12002],{"class":11804},"            backend",[1120,12004,1651],{"class":1133},[1120,12006,12008,12011],{"class":1122,"line":12007},26,[1120,12009,12010],{"class":11804},"              service",[1120,12012,1651],{"class":1133},[1120,12014,12016,12019,12021],{"class":1122,"line":12015},27,[1120,12017,12018],{"class":11804},"                name",[1120,12020,9703],{"class":1133},[1120,12022,11837],{"class":1866},[1120,12024,12026,12029],{"class":1122,"line":12025},28,[1120,12027,12028],{"class":11804},"                port",[1120,12030,1651],{"class":1133},[1120,12032,12034,12037,12039],{"class":1122,"line":12033},29,[1120,12035,12036],{"class":11804},"                  number",[1120,12038,9703],{"class":1133},[1120,12040,11881],{"class":1207},[895,12042],{},[903,12044,12046],{"id":12045},"q86-如何做滚动更新","Q86: 如何做滚动更新",[1112,12048,12050],{"className":11790,"code":12049,"language":11792,"meta":11,"style":11},"apiVersion: apps\u002Fv1\nkind: Deployment\nmetadata:\n  name: myapp\nspec:\n  replicas: 3\n  strategy:\n    type: RollingUpdate\n    rollingUpdate:\n      maxSurge: 1        # 最多多 1 个 Pod\n      maxUnavailable: 0  # 最少可用数\n",[936,12051,12052,12061,12070,12076,12084,12090,12100,12107,12117,12124,12136],{"__ignoreMap":11},[1120,12053,12054,12056,12058],{"class":1122,"line":1123},[1120,12055,11805],{"class":11804},[1120,12057,9703],{"class":1133},[1120,12059,12060],{"class":1866},"apps\u002Fv1\n",[1120,12062,12063,12065,12067],{"class":1122,"line":1130},[1120,12064,11815],{"class":11804},[1120,12066,9703],{"class":1133},[1120,12068,12069],{"class":1866},"Deployment\n",[1120,12071,12072,12074],{"class":1122,"line":1156},[1120,12073,11825],{"class":11804},[1120,12075,1651],{"class":1133},[1120,12077,12078,12080,12082],{"class":1122,"line":1177},[1120,12079,11832],{"class":11804},[1120,12081,9703],{"class":1133},[1120,12083,11861],{"class":1866},[1120,12085,12086,12088],{"class":1122,"line":1184},[1120,12087,11842],{"class":11804},[1120,12089,1651],{"class":1133},[1120,12091,12092,12095,12097],{"class":1122,"line":1190},[1120,12093,12094],{"class":11804},"  replicas",[1120,12096,9703],{"class":1133},[1120,12098,12099],{"class":1207},"3\n",[1120,12101,12102,12105],{"class":1122,"line":1221},[1120,12103,12104],{"class":11804},"  strategy",[1120,12106,1651],{"class":1133},[1120,12108,12109,12112,12114],{"class":1122,"line":1251},[1120,12110,12111],{"class":11804},"    type",[1120,12113,9703],{"class":1133},[1120,12115,12116],{"class":1866},"RollingUpdate\n",[1120,12118,12119,12122],{"class":1122,"line":1504},[1120,12120,12121],{"class":11804},"    rollingUpdate",[1120,12123,1651],{"class":1133},[1120,12125,12126,12129,12131,12133],{"class":1122,"line":1524},[1120,12127,12128],{"class":11804},"      maxSurge",[1120,12130,9703],{"class":1133},[1120,12132,5369],{"class":1207},[1120,12134,12135],{"class":1126},"        # 最多多 1 个 Pod\n",[1120,12137,12138,12141,12143,12145],{"class":1122,"line":1537},[1120,12139,12140],{"class":11804},"      maxUnavailable",[1120,12142,9703],{"class":1133},[1120,12144,1208],{"class":1207},[1120,12146,12147],{"class":1126},"  # 最少可用数\n",[892,12149,12150],{},[1042,12151,12152],{},"发布命令：",[1112,12154,12156],{"className":5404,"code":12155,"language":5406,"meta":11,"style":11},"kubectl set image deployment\u002Fmyapp myapp=myapp:v2\nkubectl rollout status deployment\u002Fmyapp\nkubectl rollout undo deployment\u002Fmyapp  # 回滚\n",[936,12157,12158,12175,12188],{"__ignoreMap":11},[1120,12159,12160,12163,12166,12169,12172],{"class":1122,"line":1123},[1120,12161,12162],{"class":1141},"kubectl",[1120,12164,12165],{"class":1866}," set",[1120,12167,12168],{"class":1866}," image",[1120,12170,12171],{"class":1866}," deployment\u002Fmyapp",[1120,12173,12174],{"class":1866}," myapp=myapp:v2\n",[1120,12176,12177,12179,12182,12185],{"class":1122,"line":1130},[1120,12178,12162],{"class":1141},[1120,12180,12181],{"class":1866}," rollout",[1120,12183,12184],{"class":1866}," status",[1120,12186,12187],{"class":1866}," deployment\u002Fmyapp\n",[1120,12189,12190,12192,12194,12197,12199],{"class":1122,"line":1156},[1120,12191,12162],{"class":1141},[1120,12193,12181],{"class":1866},[1120,12195,12196],{"class":1866}," undo",[1120,12198,12171],{"class":1866},[1120,12200,12201],{"class":1126},"  # 回滚\n",[895,12203],{},[898,12205,12207],{"id":12206},"十三工程能力","十三、工程能力",[903,12209,12211],{"id":12210},"q87-go-项目常见目录结构","Q87: Go 项目常见目录结构",[1112,12213,12216],{"className":12214,"code":12215,"language":7084},[7082],"project\u002F\n├── cmd\u002F                # 入口\n│   └── server\u002F\n│       └── main.go\n├── internal\u002F           # 私有代码\n│   ├── handler\u002F        # HTTP 处理\n│   ├── service\u002F        # 业务逻辑\n│   ├── repository\u002F     # 数据访问\n│   └── model\u002F          # 数据模型\n├── pkg\u002F                # 可导出的公共包\n├── api\u002F                # API 定义（proto\u002Fswagger）\n├── configs\u002F            # 配置文件\n├── scripts\u002F            # 脚本\n├── test\u002F               # 测试\n├── go.mod\n└── Makefile\n",[936,12217,12215],{"__ignoreMap":11},[895,12219],{},[903,12221,12223],{"id":12222},"q88-如何写单元测试","Q88: 如何写单元测试",[1112,12225,12227],{"className":1114,"code":12226,"language":1116,"meta":11,"style":11},"\u002F\u002F user_service_test.go\nfunc TestCreateUser(t *testing.T) {\n    \u002F\u002F Arrange\n    mockRepo := &MockUserRepo{}\n    service := NewUserService(mockRepo)\n    \n    mockRepo.On(\"Create\", mock.Anything).Return(nil)\n    \n    \u002F\u002F Act\n    err := service.Create(&User{Name: \"test\"})\n    \n    \u002F\u002F Assert\n    assert.NoError(t, err)\n    mockRepo.AssertExpectations(t)\n}\n\n\u002F\u002F 表驱动测试\nfunc TestAdd(t *testing.T) {\n    tests := []struct {\n        name     string\n        a, b     int\n        expected int\n    }{\n        {\"positive\", 1, 2, 3},\n        {\"negative\", -1, -2, -3},\n        {\"zero\", 0, 0, 0},\n    }\n    \n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            result := Add(tt.a, tt.b)\n            assert.Equal(t, tt.expected, result)\n        })\n    }\n}\n",[936,12228,12229,12234,12255,12260,12274,12287,12291,12316,12320,12325,12351,12355,12360,12371,12380,12384,12388,12393,12414,12428,12435,12442,12449,12454,12477,12505,12526,12530,12534,12548,12575,12589,12601,12606,12611],{"__ignoreMap":11},[1120,12230,12231],{"class":1122,"line":1123},[1120,12232,12233],{"class":1126},"\u002F\u002F user_service_test.go\n",[1120,12235,12236,12238,12241,12243,12245,12247,12249,12251,12253],{"class":1122,"line":1130},[1120,12237,1440],{"class":1137},[1120,12239,12240],{"class":1141}," TestCreateUser",[1120,12242,1145],{"class":1133},[1120,12244,6719],{"class":1515},[1120,12246,6355],{"class":1137},[1120,12248,6724],{"class":1141},[1120,12250,2167],{"class":1133},[1120,12252,1088],{"class":1141},[1120,12254,1521],{"class":1133},[1120,12256,12257],{"class":1122,"line":1156},[1120,12258,12259],{"class":1126},"    \u002F\u002F Arrange\n",[1120,12261,12262,12265,12267,12269,12272],{"class":1122,"line":1177},[1120,12263,12264],{"class":1133},"    mockRepo ",[1120,12266,1138],{"class":1137},[1120,12268,2019],{"class":1137},[1120,12270,12271],{"class":1141},"MockUserRepo",[1120,12273,8028],{"class":1133},[1120,12275,12276,12279,12281,12284],{"class":1122,"line":1184},[1120,12277,12278],{"class":1133},"    service ",[1120,12280,1138],{"class":1137},[1120,12282,12283],{"class":1141}," NewUserService",[1120,12285,12286],{"class":1133},"(mockRepo)\n",[1120,12288,12289],{"class":1122,"line":1190},[1120,12290,2811],{"class":1133},[1120,12292,12293,12296,12299,12301,12304,12307,12310,12312,12314],{"class":1122,"line":1221},[1120,12294,12295],{"class":1133},"    mockRepo.",[1120,12297,12298],{"class":1141},"On",[1120,12300,1145],{"class":1133},[1120,12302,12303],{"class":1866},"\"Create\"",[1120,12305,12306],{"class":1133},", mock.Anything).",[1120,12308,12309],{"class":1141},"Return",[1120,12311,1145],{"class":1133},[1120,12313,2686],{"class":1207},[1120,12315,2591],{"class":1133},[1120,12317,12318],{"class":1122,"line":1251},[1120,12319,2811],{"class":1133},[1120,12321,12322],{"class":1122,"line":1504},[1120,12323,12324],{"class":1126},"    \u002F\u002F Act\n",[1120,12326,12327,12330,12332,12335,12338,12340,12342,12344,12346,12349],{"class":1122,"line":1524},[1120,12328,12329],{"class":1133},"    err ",[1120,12331,1138],{"class":1137},[1120,12333,12334],{"class":1133}," service.",[1120,12336,12337],{"class":1141},"Create",[1120,12339,1145],{"class":1133},[1120,12341,2385],{"class":1137},[1120,12343,1989],{"class":1141},[1120,12345,2004],{"class":1133},[1120,12347,12348],{"class":1866},"\"test\"",[1120,12350,8958],{"class":1133},[1120,12352,12353],{"class":1122,"line":1537},[1120,12354,2811],{"class":1133},[1120,12356,12357],{"class":1122,"line":1548},[1120,12358,12359],{"class":1126},"    \u002F\u002F Assert\n",[1120,12361,12362,12365,12368],{"class":1122,"line":2333},[1120,12363,12364],{"class":1133},"    assert.",[1120,12366,12367],{"class":1141},"NoError",[1120,12369,12370],{"class":1133},"(t, err)\n",[1120,12372,12373,12375,12378],{"class":1122,"line":2339},[1120,12374,12295],{"class":1133},[1120,12376,12377],{"class":1141},"AssertExpectations",[1120,12379,6743],{"class":1133},[1120,12381,12382],{"class":1122,"line":2344},[1120,12383,1404],{"class":1133},[1120,12385,12386],{"class":1122,"line":2349},[1120,12387,1181],{"emptyLinePlaceholder":1180},[1120,12389,12390],{"class":1122,"line":2355},[1120,12391,12392],{"class":1126},"\u002F\u002F 表驱动测试\n",[1120,12394,12395,12397,12400,12402,12404,12406,12408,12410,12412],{"class":1122,"line":2372},[1120,12396,1440],{"class":1137},[1120,12398,12399],{"class":1141}," TestAdd",[1120,12401,1145],{"class":1133},[1120,12403,6719],{"class":1515},[1120,12405,6355],{"class":1137},[1120,12407,6724],{"class":1141},[1120,12409,2167],{"class":1133},[1120,12411,1088],{"class":1141},[1120,12413,1521],{"class":1133},[1120,12415,12416,12419,12421,12423,12426],{"class":1122,"line":2391},[1120,12417,12418],{"class":1133},"    tests ",[1120,12420,1138],{"class":1137},[1120,12422,3488],{"class":1133},[1120,12424,12425],{"class":1137},"struct",[1120,12427,1334],{"class":1133},[1120,12429,12430,12433],{"class":1122,"line":2402},[1120,12431,12432],{"class":1133},"        name     ",[1120,12434,1839],{"class":1137},[1120,12436,12437,12440],{"class":1122,"line":3100},[1120,12438,12439],{"class":1133},"        a, b     ",[1120,12441,1847],{"class":1137},[1120,12443,12444,12447],{"class":1122,"line":3106},[1120,12445,12446],{"class":1133},"        expected ",[1120,12448,1847],{"class":1137},[1120,12450,12451],{"class":1122,"line":9843},[1120,12452,12453],{"class":1133},"    }{\n",[1120,12455,12456,12459,12462,12464,12466,12468,12470,12472,12474],{"class":1122,"line":9848},[1120,12457,12458],{"class":1133},"        {",[1120,12460,12461],{"class":1866},"\"positive\"",[1120,12463,949],{"class":1133},[1120,12465,5369],{"class":1207},[1120,12467,949],{"class":1133},[1120,12469,6214],{"class":1207},[1120,12471,949],{"class":1133},[1120,12473,8865],{"class":1207},[1120,12475,12476],{"class":1133},"},\n",[1120,12478,12479,12481,12484,12486,12489,12491,12493,12495,12497,12499,12501,12503],{"class":1122,"line":11999},[1120,12480,12458],{"class":1133},[1120,12482,12483],{"class":1866},"\"negative\"",[1120,12485,949],{"class":1133},[1120,12487,12488],{"class":1137},"-",[1120,12490,5369],{"class":1207},[1120,12492,949],{"class":1133},[1120,12494,12488],{"class":1137},[1120,12496,6214],{"class":1207},[1120,12498,949],{"class":1133},[1120,12500,12488],{"class":1137},[1120,12502,8865],{"class":1207},[1120,12504,12476],{"class":1133},[1120,12506,12507,12509,12512,12514,12516,12518,12520,12522,12524],{"class":1122,"line":12007},[1120,12508,12458],{"class":1133},[1120,12510,12511],{"class":1866},"\"zero\"",[1120,12513,949],{"class":1133},[1120,12515,1208],{"class":1207},[1120,12517,949],{"class":1133},[1120,12519,1208],{"class":1207},[1120,12521,949],{"class":1133},[1120,12523,1208],{"class":1207},[1120,12525,12476],{"class":1133},[1120,12527,12528],{"class":1122,"line":12015},[1120,12529,5381],{"class":1133},[1120,12531,12532],{"class":1122,"line":12025},[1120,12533,2811],{"class":1133},[1120,12535,12536,12538,12541,12543,12545],{"class":1122,"line":12033},[1120,12537,6535],{"class":1137},[1120,12539,12540],{"class":1133}," _, tt ",[1120,12542,1138],{"class":1137},[1120,12544,4198],{"class":1137},[1120,12546,12547],{"class":1133}," tests {\n",[1120,12549,12551,12554,12556,12559,12561,12563,12565,12567,12569,12571,12573],{"class":1122,"line":12550},30,[1120,12552,12553],{"class":1133},"        t.",[1120,12555,8710],{"class":1141},[1120,12557,12558],{"class":1133},"(tt.name, ",[1120,12560,1440],{"class":1137},[1120,12562,1145],{"class":1133},[1120,12564,6719],{"class":1515},[1120,12566,6355],{"class":1137},[1120,12568,6724],{"class":1141},[1120,12570,2167],{"class":1133},[1120,12572,1088],{"class":1141},[1120,12574,1521],{"class":1133},[1120,12576,12578,12581,12583,12586],{"class":1122,"line":12577},31,[1120,12579,12580],{"class":1133},"            result ",[1120,12582,1138],{"class":1137},[1120,12584,12585],{"class":1141}," Add",[1120,12587,12588],{"class":1133},"(tt.a, tt.b)\n",[1120,12590,12592,12595,12598],{"class":1122,"line":12591},32,[1120,12593,12594],{"class":1133},"            assert.",[1120,12596,12597],{"class":1141},"Equal",[1120,12599,12600],{"class":1133},"(t, tt.expected, result)\n",[1120,12602,12604],{"class":1122,"line":12603},33,[1120,12605,10219],{"class":1133},[1120,12607,12609],{"class":1122,"line":12608},34,[1120,12610,5381],{"class":1133},[1120,12612,12614],{"class":1122,"line":12613},35,[1120,12615,1404],{"class":1133},[895,12617],{},[903,12619,12621],{"id":12620},"q89-mock-怎么做","Q89: Mock 怎么做",[892,12623,12624],{},[1042,12625,12626],{},"常用 Mock 库：",[908,12628,12629,12637],{},[911,12630,12631],{},[914,12632,12633,12635],{},[917,12634,11465],{"align":919},[917,12636,10346],{"align":919},[925,12638,12639,12647,12655],{},[914,12640,12641,12644],{},[930,12642,12643],{"align":919},"gomock",[930,12645,12646],{"align":919},"官方，代码生成",[914,12648,12649,12652],{},[930,12650,12651],{"align":919},"testify\u002Fmock",[930,12653,12654],{"align":919},"简单易用",[914,12656,12657,12660],{},[930,12658,12659],{"align":919},"mockery",[930,12661,12662],{"align":919},"自动生成 mock",[1112,12664,12666],{"className":1114,"code":12665,"language":1116,"meta":11,"style":11},"\u002F\u002F 使用 testify\u002Fmock\ntype MockUserRepo struct {\n    mock.Mock\n}\n\nfunc (m *MockUserRepo) GetByID(id int64) (*User, error) {\n    args := m.Called(id)\n    return args.Get(0).(*User), args.Error(1)\n}\n\n\u002F\u002F 测试中使用\nmockRepo.On(\"GetByID\", int64(1)).Return(&User{ID: 1}, nil)\n",[936,12667,12668,12673,12684,12694,12698,12702,12738,12754,12784,12788,12792,12797],{"__ignoreMap":11},[1120,12669,12670],{"class":1122,"line":1123},[1120,12671,12672],{"class":1126},"\u002F\u002F 使用 testify\u002Fmock\n",[1120,12674,12675,12677,12680,12682],{"class":1122,"line":1130},[1120,12676,1325],{"class":1137},[1120,12678,12679],{"class":1141}," MockUserRepo",[1120,12681,1331],{"class":1137},[1120,12683,1334],{"class":1133},[1120,12685,12686,12689,12691],{"class":1122,"line":1156},[1120,12687,12688],{"class":1141},"    mock",[1120,12690,2167],{"class":1133},[1120,12692,12693],{"class":1141},"Mock\n",[1120,12695,12696],{"class":1122,"line":1177},[1120,12697,1404],{"class":1133},[1120,12699,12700],{"class":1122,"line":1184},[1120,12701,1181],{"emptyLinePlaceholder":1180},[1120,12703,12704,12706,12708,12710,12712,12714,12716,12719,12721,12724,12726,12728,12730,12732,12734,12736],{"class":1122,"line":1190},[1120,12705,1440],{"class":1137},[1120,12707,2508],{"class":1133},[1120,12709,1224],{"class":1515},[1120,12711,1380],{"class":1137},[1120,12713,12271],{"class":1141},[1120,12715,2519],{"class":1133},[1120,12717,12718],{"class":1141},"GetByID",[1120,12720,1145],{"class":1133},[1120,12722,12723],{"class":1515},"id",[1120,12725,5293],{"class":1137},[1120,12727,10544],{"class":1133},[1120,12729,1380],{"class":1137},[1120,12731,1989],{"class":1141},[1120,12733,949],{"class":1133},[1120,12735,2857],{"class":1137},[1120,12737,1521],{"class":1133},[1120,12739,12740,12743,12745,12748,12751],{"class":1122,"line":1221},[1120,12741,12742],{"class":1133},"    args ",[1120,12744,1138],{"class":1137},[1120,12746,12747],{"class":1133}," m.",[1120,12749,12750],{"class":1141},"Called",[1120,12752,12753],{"class":1133},"(id)\n",[1120,12755,12756,12758,12761,12763,12765,12767,12769,12771,12773,12776,12778,12780,12782],{"class":1122,"line":1251},[1120,12757,1482],{"class":1137},[1120,12759,12760],{"class":1133}," args.",[1120,12762,7714],{"class":1141},[1120,12764,1145],{"class":1133},[1120,12766,1208],{"class":1207},[1120,12768,6440],{"class":1133},[1120,12770,1380],{"class":1137},[1120,12772,1989],{"class":1141},[1120,12774,12775],{"class":1133},"), args.",[1120,12777,2522],{"class":1141},[1120,12779,1145],{"class":1133},[1120,12781,5369],{"class":1207},[1120,12783,2591],{"class":1133},[1120,12785,12786],{"class":1122,"line":1504},[1120,12787,1404],{"class":1133},[1120,12789,12790],{"class":1122,"line":1524},[1120,12791,1181],{"emptyLinePlaceholder":1180},[1120,12793,12794],{"class":1122,"line":1537},[1120,12795,12796],{"class":1126},"\u002F\u002F 测试中使用\n",[1120,12798,12799,12802,12804,12806,12809,12811,12813,12815,12817,12820,12822,12824,12826,12828,12831,12833,12836,12838],{"class":1122,"line":1548},[1120,12800,12801],{"class":1133},"mockRepo.",[1120,12803,12298],{"class":1141},[1120,12805,1145],{"class":1133},[1120,12807,12808],{"class":1866},"\"GetByID\"",[1120,12810,949],{"class":1133},[1120,12812,961],{"class":1137},[1120,12814,1145],{"class":1133},[1120,12816,5369],{"class":1207},[1120,12818,12819],{"class":1133},")).",[1120,12821,12309],{"class":1141},[1120,12823,1145],{"class":1133},[1120,12825,2385],{"class":1137},[1120,12827,1989],{"class":1141},[1120,12829,12830],{"class":1133},"{ID: ",[1120,12832,5369],{"class":1207},[1120,12834,12835],{"class":1133},"}, ",[1120,12837,2686],{"class":1207},[1120,12839,2591],{"class":1133},[895,12841],{},[903,12843,12845],{"id":12844},"q90-codereview-关注什么","Q90: CodeReview 关注什么",[908,12847,12848,12858],{},[911,12849,12850],{},[914,12851,12852,12855],{},[917,12853,12854],{"align":919},"方面",[917,12856,12857],{"align":919},"关注点",[925,12859,12860,12870,12880,12889,12899,12909],{},[914,12861,12862,12867],{},[930,12863,12864],{"align":919},[1042,12865,12866],{},"正确性",[930,12868,12869],{"align":919},"逻辑是否正确，边界条件",[914,12871,12872,12877],{},[930,12873,12874],{"align":919},[1042,12875,12876],{},"安全性",[930,12878,12879],{"align":919},"SQL注入、XSS、权限校验",[914,12881,12882,12886],{},[930,12883,12884],{"align":919},[1042,12885,3225],{},[930,12887,12888],{"align":919},"N+1 查询、大循环、锁粒度",[914,12890,12891,12896],{},[930,12892,12893],{"align":919},[1042,12894,12895],{},"可读性",[930,12897,12898],{"align":919},"命名、注释、函数长度",[914,12900,12901,12906],{},[930,12902,12903],{"align":919},[1042,12904,12905],{},"可测试性",[930,12907,12908],{"align":919},"依赖注入、接口抽象",[914,12910,12911,12915],{},[930,12912,12913],{"align":919},[1042,12914,9417],{},[930,12916,12917],{"align":919},"error 是否正确处理",[895,12919],{},[898,12921,12923],{"id":12922},"十四高频考点清单","十四、高频考点清单",[903,12925,12926],{"id":12926},"必考",[1667,12928,12931,12940,12946,12952,12958,12964,12970],{"className":12929},[12930],"contains-task-list",[1293,12932,12935,12939],{"className":12933},[12934],"task-list-item",[12936,12937],"input",{"disabled":1180,"type":12938},"checkbox"," slice\u002Fmap 底层结构和扩容",[1293,12941,12943,12945],{"className":12942},[12934],[12936,12944],{"disabled":1180,"type":12938}," Goroutine vs 线程、GMP 模型",[1293,12947,12949,12951],{"className":12948},[12934],[12936,12950],{"disabled":1180,"type":12938}," Channel 底层和操作表",[1293,12953,12955,12957],{"className":12954},[12934],[12936,12956],{"disabled":1180,"type":12938}," GC 三色标记、写屏障",[1293,12959,12961,12963],{"className":12960},[12934],[12936,12962],{"disabled":1180,"type":12938}," 逃逸分析",[1293,12965,12967,12969],{"className":12966},[12934],[12936,12968],{"disabled":1180,"type":12938}," Context 使用",[1293,12971,12973,12975],{"className":12972},[12934],[12936,12974],{"disabled":1180,"type":12938}," Gin 中间件原理",[903,12977,12978],{"id":12978},"常考",[1667,12980,12982,12988,12994,13000,13006,13012,13018],{"className":12981},[12930],[1293,12983,12985,12987],{"className":12984},[12934],[12936,12986],{"disabled":1180,"type":12938}," defer 执行顺序",[1293,12989,12991,12993],{"className":12990},[12934],[12936,12992],{"disabled":1180,"type":12938}," select 用法",[1293,12995,12997,12999],{"className":12996},[12934],[12936,12998],{"disabled":1180,"type":12938}," sync.Mutex vs RWMutex",[1293,13001,13003,13005],{"className":13002},[12934],[12936,13004],{"disabled":1180,"type":12938}," sync.Pool 原理",[1293,13007,13009,13011],{"className":13008},[12934],[12936,13010],{"disabled":1180,"type":12938}," pprof 使用",[1293,13013,13015,13017],{"className":13014},[12934],[12936,13016],{"disabled":1180,"type":12938}," 限流算法",[1293,13019,13021,13023],{"className":13020},[12934],[12936,13022],{"disabled":1180,"type":12938}," 缓存一致性",[903,13025,13026],{"id":13026},"进阶",[1667,13028,13030,13036,13042,13048,13054,13060],{"className":13029},[12930],[1293,13031,13033,13035],{"className":13032},[12934],[12936,13034],{"disabled":1180,"type":12938}," 系统设计（高并发、高可用）",[1293,13037,13039,13041],{"className":13038},[12934],[12936,13040],{"disabled":1180,"type":12938}," 熔断降级实现",[1293,13043,13045,13047],{"className":13044},[12934],[12936,13046],{"disabled":1180,"type":12938}," Goroutine 泄漏检测",[1293,13049,13051,13053],{"className":13050},[12934],[12936,13052],{"disabled":1180,"type":12938}," 内存泄漏排查",[1293,13055,13057,13059],{"className":13056},[12934],[12936,13058],{"disabled":1180,"type":12938}," Docker\u002FK8s 部署",[1293,13061,13063,13065],{"className":13062},[12934],[12936,13064],{"disabled":1180,"type":12938}," 单元测试和 Mock",[13067,13068,13069],"style",{},"html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sxrX7, html code.shiki .sxrX7{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s8jYJ, html code.shiki .s8jYJ{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .snPdu, html code.shiki .snPdu{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sBjJW, html code.shiki .sBjJW{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sP4rz, html code.shiki .sP4rz{--shiki-light:#E36209;--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sIIMD, html code.shiki .sIIMD{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sovSZ, html code.shiki .sovSZ{--shiki-light:#22863A;--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":11,"searchDepth":1130,"depth":1130,"links":13071},[13072,13087,13098,13121,13127,13133,13139,13146,13155,13163,13169,13176,13182,13188],{"id":900,"depth":1130,"text":901,"children":13073},[13074,13075,13076,13077,13078,13079,13080,13081,13082,13083,13084,13085,13086],{"id":905,"depth":1156,"text":906},{"id":1053,"depth":1156,"text":1054},{"id":1282,"depth":1156,"text":1283},{"id":1555,"depth":1156,"text":1556},{"id":1682,"depth":1156,"text":1683},{"id":1764,"depth":1156,"text":1765},{"id":1964,"depth":1156,"text":1965},{"id":2050,"depth":1156,"text":2051},{"id":2182,"depth":1156,"text":2183},{"id":2457,"depth":1156,"text":2458},{"id":2629,"depth":1156,"text":2630},{"id":2832,"depth":1156,"text":2833},{"id":2920,"depth":1156,"text":2921},{"id":3133,"depth":1130,"text":3134,"children":13088},[13089,13090,13091,13092,13093,13094,13095,13096,13097],{"id":3137,"depth":1156,"text":3138},{"id":3284,"depth":1156,"text":3285},{"id":3455,"depth":1156,"text":3456},{"id":3605,"depth":1156,"text":3606},{"id":3690,"depth":1156,"text":3691},{"id":3807,"depth":1156,"text":3808},{"id":3833,"depth":1156,"text":3834},{"id":4144,"depth":1156,"text":4145},{"id":4260,"depth":1156,"text":4261},{"id":4370,"depth":1130,"text":4371,"children":13099},[13100,13101,13102,13103,13104,13105,13106,13107,13108,13109,13110,13111,13112,13113,13114,13115,13116,13117,13118,13119,13120],{"id":4374,"depth":1156,"text":4375},{"id":4481,"depth":1156,"text":4482},{"id":4567,"depth":1156,"text":4568},{"id":4611,"depth":1156,"text":4612},{"id":4738,"depth":1156,"text":4739},{"id":4823,"depth":1156,"text":4824},{"id":4876,"depth":1156,"text":4877},{"id":4944,"depth":1156,"text":4945},{"id":5012,"depth":1156,"text":5013},{"id":5085,"depth":1156,"text":5086},{"id":5180,"depth":1156,"text":5181},{"id":5250,"depth":1156,"text":5251},{"id":5395,"depth":1156,"text":5396},{"id":5450,"depth":1156,"text":5451},{"id":5642,"depth":1156,"text":5643},{"id":5787,"depth":1156,"text":5788},{"id":5869,"depth":1156,"text":5870},{"id":6049,"depth":1156,"text":6050},{"id":6484,"depth":1156,"text":6485},{"id":6635,"depth":1156,"text":6636},{"id":6757,"depth":1156,"text":6758},{"id":6829,"depth":1130,"text":6830,"children":13122},[13123,13124,13125,13126],{"id":6833,"depth":1156,"text":6834},{"id":6924,"depth":1156,"text":6925},{"id":6961,"depth":1156,"text":6962},{"id":6983,"depth":1156,"text":6984},{"id":7018,"depth":1130,"text":7019,"children":13128},[13129,13130,13131,13132],{"id":7022,"depth":1156,"text":7023},{"id":7072,"depth":1156,"text":7073},{"id":7130,"depth":1156,"text":7131},{"id":7235,"depth":1156,"text":7236},{"id":7278,"depth":1130,"text":7279,"children":13134},[13135,13136,13137,13138],{"id":7282,"depth":1156,"text":7283},{"id":7343,"depth":1156,"text":7344},{"id":7437,"depth":1156,"text":7438},{"id":7457,"depth":1156,"text":7458},{"id":7498,"depth":1130,"text":7499,"children":13140},[13141,13142,13143,13144,13145],{"id":7502,"depth":1156,"text":7503},{"id":7624,"depth":1156,"text":7625},{"id":7764,"depth":1156,"text":7765},{"id":7942,"depth":1156,"text":7943},{"id":8049,"depth":1156,"text":8050},{"id":8183,"depth":1130,"text":8184,"children":13147},[13148,13149,13150,13151,13152,13153,13154],{"id":8187,"depth":1156,"text":8188},{"id":8336,"depth":1156,"text":8337},{"id":8513,"depth":1156,"text":8514},{"id":8744,"depth":1156,"text":8745},{"id":8799,"depth":1156,"text":8800},{"id":9013,"depth":1156,"text":9014},{"id":9092,"depth":1156,"text":9093},{"id":9274,"depth":1130,"text":9275,"children":13156},[13157,13158,13159,13160,13161,13162],{"id":9278,"depth":1156,"text":9279},{"id":9422,"depth":1156,"text":9423},{"id":9588,"depth":1156,"text":9589},{"id":9855,"depth":1156,"text":9856},{"id":10035,"depth":1156,"text":10036},{"id":10047,"depth":1156,"text":10048},{"id":10246,"depth":1130,"text":10247,"children":13164},[13165,13166,13167,13168],{"id":10250,"depth":1156,"text":10251},{"id":10333,"depth":1156,"text":10334},{"id":10516,"depth":1156,"text":10517},{"id":10727,"depth":1156,"text":10728},{"id":10979,"depth":1130,"text":10980,"children":13170},[13171,13172,13173,13174,13175],{"id":10983,"depth":1156,"text":10984},{"id":11179,"depth":1156,"text":11180},{"id":11298,"depth":1156,"text":11299},{"id":11395,"depth":1156,"text":11396},{"id":11455,"depth":1156,"text":11456},{"id":11566,"depth":1130,"text":11567,"children":13177},[13178,13179,13180,13181],{"id":11570,"depth":1156,"text":11571},{"id":11708,"depth":1156,"text":11709},{"id":11786,"depth":1156,"text":11787},{"id":12045,"depth":1156,"text":12046},{"id":12206,"depth":1130,"text":12207,"children":13183},[13184,13185,13186,13187],{"id":12210,"depth":1156,"text":12211},{"id":12222,"depth":1156,"text":12223},{"id":12620,"depth":1156,"text":12621},{"id":12844,"depth":1156,"text":12845},{"id":12922,"depth":1130,"text":12923,"children":13189},[13190,13191,13192],{"id":12926,"depth":1156,"text":12926},{"id":12978,"depth":1156,"text":12978},{"id":13026,"depth":1156,"text":13026},"md",{},{"title":338,"description":339},"interview\u002Fgolang","xFnvAjGfsMcLMJOmOxZdGtoqJog-Mjll5OMX3iqQ8KY",1775496409409]