-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
534 lines (251 loc) · 481 KB
/
Copy pathatom.xml
File metadata and controls
534 lines (251 loc) · 481 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Deng的博客</title>
<link href="http://coderedeng.github.io/atom.xml" rel="self"/>
<link href="http://coderedeng.github.io/"/>
<updated>2026-06-18T07:04:03.685Z</updated>
<id>http://coderedeng.github.io/</id>
<author>
<name>Evan Deng</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>微软MAI Seven深度解析:Build 2026发布七款自研AI模型,AI独立战略迈出关键一步</title>
<link href="http://coderedeng.github.io/2026/06/18/%E5%BE%AE%E8%BD%AFMAI-Seven%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-Build-2026%E5%8F%91%E5%B8%83%E4%B8%83%E6%AC%BE%E8%87%AA%E7%A0%94AI%E6%A8%A1%E5%9E%8B/"/>
<id>http://coderedeng.github.io/2026/06/18/%E5%BE%AE%E8%BD%AFMAI-Seven%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-Build-2026%E5%8F%91%E5%B8%83%E4%B8%83%E6%AC%BE%E8%87%AA%E7%A0%94AI%E6%A8%A1%E5%9E%8B/</id>
<published>2026-06-18T14:00:00.000Z</published>
<updated>2026-06-18T07:04:03.685Z</updated>
<content type="html"><![CDATA[<h2 id="引言:微软告别”代工厂”时代"><a href="#引言:微软告别”代工厂”时代" class="headerlink" title="引言:微软告别”代工厂”时代"></a>引言:微软告别”代工厂”时代</h2><p>在刚刚落幕的 Microsoft Build 2026 大会上,一个曾被外界视为”不可能”的时刻正式到来——微软首次完整展示了其自研 AI 模型家族 <strong>MAI Seven</strong>(Microsoft AI Superintelligence),共包含七款覆盖推理、代码生成、图像理解、语音转录和声音合成的全栈模型。</p><p>这标志着自 2019 年与 OpenAI 达成战略合作以来,微软在 AI 领域的战略姿态发生了根本性转变:从”OpenAI 的超级客户”到”拥有自主核心技术的全栈 AI 供应商”。</p><h2 id="MAI-Seven-家族全景"><a href="#MAI-Seven-家族全景" class="headerlink" title="MAI Seven 家族全景"></a>MAI Seven 家族全景</h2><h3 id="1-MAI-Thinking-1-—-旗舰推理模型"><a href="#1-MAI-Thinking-1-—-旗舰推理模型" class="headerlink" title="1. MAI-Thinking-1 — 旗舰推理模型"></a>1. MAI-Thinking-1 — 旗舰推理模型</h3><p>MAI-Thinking-1 是整个家族的核心,也是微软首款推理专用模型。它采用<strong>混合专家(MoE)架构</strong>,拥有约 <strong>2000 亿总参数、350 亿激活参数</strong>,支持 <strong>256K token 上下文窗口</strong>。</p><p>在基准测试中表现亮眼:</p><ul><li><strong>AIME 2026</strong>: 超越 GPT-5.5(OpenAI 当前旗舰),进入全球推理模型前三行列</li><li><strong>MMLU-Pro</strong>: 准确率达到行业领先水平</li><li><strong>代码生成 (LiveCodeBench)</strong>: 显著优于同量级闭源模型</li></ul><p>其核心设计理念是”用更少的激活参数实现更强的推理能力”——MoE 架构使得每次前向传播只需激活约 17.5% 的参数,大幅降低了推理成本。</p><h3 id="2-MAI-Code-1-Flash-—-已入驻-Copilot-的代码引擎"><a href="#2-MAI-Code-1-Flash-—-已入驻-Copilot-的代码引擎" class="headerlink" title="2. MAI-Code-1-Flash — 已入驻 Copilot 的代码引擎"></a>2. MAI-Code-1-Flash — 已入驻 Copilot 的代码引擎</h3><p>如果说 Thinking-1 是理论上的王者,MAI-Code-1-Flash 就是<strong>已经投入实战的利器</strong>。这款仅 <strong>50 亿参数</strong>的小模型已在 Build 大会前悄悄集成到 GitHub Copilot 中。</p><p>关键特性:</p><ul><li><strong>极致效率</strong>: 参数量仅为 Thinking-1 的约 1.4%,推理速度提升数倍</li><li><strong>Copilot 实测</strong>: 开发者反馈代码补全质量和响应速度均有明显提升</li><li><strong>开源友好</strong>: 微软已计划在 Foundry 平台上开放 API 调用</li></ul><h3 id="3-MAI-Image-2-5-—-图像理解与生成"><a href="#3-MAI-Image-2-5-—-图像理解与生成" class="headerlink" title="3. MAI-Image-2.5 — 图像理解与生成"></a>3. MAI-Image-2.5 — 图像理解与生成</h3><p>作为多模态能力的关键一环,MAI-Image-2.5 支持从图像描述、视觉问答到指令驱动的图像生成等多种任务。虽然在公开测试中尚未直接对标 DALL·E 或 Midjourney,但在<strong>与文字模型的协同理解</strong>方面展现出独特优势——例如能准确识别代码截图中的逻辑错误。</p><h3 id="4-MAI-Transcribe-1-5-amp-MAI-Voice-2-—-语音全栈能力"><a href="#4-MAI-Transcribe-1-5-amp-MAI-Voice-2-—-语音全栈能力" class="headerlink" title="4. MAI-Transcribe-1.5 & MAI-Voice-2 — 语音全栈能力"></a>4. MAI-Transcribe-1.5 & MAI-Voice-2 — 语音全栈能力</h3><p>这两者分别负责<strong>高质量语音转文本</strong>和<strong>自然声音合成</strong>。MAI-Transcribe-1.5 在多语言场景下(包括中文、日文、阿拉伯语等)的识别准确率超越了 Whisper Large v3;MAI-Voice-2 则能以极低延迟生成接近真人的语音输出,为 Copilot Voice 等功能提供底层支撑。</p><h2 id="为什么这七款模型如此重要?"><a href="#为什么这七款模型如此重要?" class="headerlink" title="为什么这七款模型如此重要?"></a>为什么这七款模型如此重要?</h2><h3 id="战略层面:从”合作”到”独立”"><a href="#战略层面:从”合作”到”独立”" class="headerlink" title="战略层面:从”合作”到”独立”"></a>战略层面:从”合作”到”独立”</h3><p>微软与 OpenAI 的关系一直微妙。虽然微软是 OpenAI 的最大投资方和云基础设施提供者(Azure 为其贡献了巨额收入),但外界普遍认为双方在模型所有权、利润分配和技术路线上的分歧日益加深。</p><p>此次 MAI Seven 的发布,实际上是微软<strong>六个月内 renegotiated OpenAI 协议</strong>后的首次重大成果展示。核心变化包括:</p><ul><li>微软获得了更明确的自研模型商业化权限</li><li>Azure 仍将是 OpenAI 的主要云提供商,但微软不再被绑定于单一外部模型</li><li>“Superintelligence Lab”的成立意味着微软将建立独立的前沿 AI 研发体系</li></ul><h3 id="技术层面:全栈覆盖-成本优势"><a href="#技术层面:全栈覆盖-成本优势" class="headerlink" title="技术层面:全栈覆盖 + 成本优势"></a>技术层面:全栈覆盖 + 成本优势</h3><p>MAI Seven 的另一个关键特征是<strong>全栈自研</strong>——从推理到代码、图像、语音,每一层都由微软自己的团队构建。这意味着:</p><ul><li><strong>更深的系统集成</strong>: Copilot、Windows AI、Azure OpenAI Service 可以获得端到端的优化</li><li><strong>显著的成本节约</strong>: 据 Zoopa 等媒体分析,MAI-Thinking-1 的推理成本预计比 GPT-5.5 <strong>低约 10 倍</strong></li><li><strong>更强的定制化能力</strong>: 微软可以根据企业客户需求快速调整模型行为</li></ul><h3 id="市场层面:AI-格局的多极化"><a href="#市场层面:AI-格局的多极化" class="headerlink" title="市场层面:AI 格局的多极化"></a>市场层面:AI 格局的多极化</h3><p>在 MAI Seven 发布之前,AI 模型的”第一梯队”几乎完全由美国公司主导(OpenAI、Google DeepMind、Anthropic)。微软的自研模型系列表明:</p><ul><li><strong>科技巨头的 AI 能力正在去中心化</strong>——不再只有 OpenAI 一家能训练前沿模型</li><li><strong>开源/闭源的边界进一步模糊</strong>: MAI-Code-1-Flash 虽未完全开源,但通过 Foundry API 的开放程度远超传统闭源模式</li><li><strong>中国模型的竞争压力</strong>(如 Moonshot AI Kimi K2)可能加速了微软的独立步伐</li></ul><h2 id="开发者视角:如何接入?"><a href="#开发者视角:如何接入?" class="headerlink" title="开发者视角:如何接入?"></a>开发者视角:如何接入?</h2><p>微软已宣布 MAI Seven 将通过以下渠道提供:</p><table><thead><tr><th>渠道</th><th>说明</th></tr></thead><tbody><tr><td><strong>Azure Foundry</strong></td><td>API 调用,支持按量付费和预留实例</td></tr><tr><td><strong>GitHub Copilot</strong></td><td>MAI-Code-1-Flash 已内置,体验升级无需额外操作</td></tr><tr><td><strong>Microsoft 365 Copilot</strong></td><td>推理和多模态能力将逐步集成到 Office 套件中</td></tr><tr><td><strong>未来开源计划</strong></td><td>微软表示部分模型(尤其是 Code 系列)将在评估后考虑开源</td></tr></tbody></table><h2 id="展望:MAI-Seven-之后是什么?"><a href="#展望:MAI-Seven-之后是什么?" class="headerlink" title="展望:MAI Seven 之后是什么?"></a>展望:MAI Seven 之后是什么?</h2><p>Build 2026 只是起点。微软 CEO 萨提亚·纳德拉在主题演讲中明确表示:”我们正在建设一台’爬山机器’——一个能够持续自我改进、不断攀登智能高峰的系统。”</p><p>这句话背后暗示了微软更宏大的愿景:<strong>MAI-Thinking-1 不是一个终点,而是一个可以自我迭代的 AI 训练基础设施</strong>。如果这一方向得到验证,我们可能会在未来 6-12 个月内看到 MAI 系列的第二代甚至第三代模型。</p><p>与此同时,OpenAI 的 GPT-5.5 系列(5.4/5.5 Pro/5.5 Instant)和 Google 的 Gemini 3.5 Flash 仍在持续进化——全球 AI 模型的军备竞赛,才刚刚进入”多极并立”的新阶段。</p><hr><p><em>本文基于 Build 2026 大会公开信息、官方技术博客及多个独立媒体报道整理而成。更多信息请访问 <a href="https://microsoft.ai/">microsoft.ai</a> 和 Azure Foundry 平台。</em></p>]]></content>
<summary type="html"><h2 id="引言:微软告别”代工厂”时代"><a href="#引言:微软告别”代工厂”时代" class="headerlink" title="引言:微软告别”代工厂”时代"></a>引言:微软告别”代工厂”时代</h2><p>在刚刚落幕的 Microsoft Build</summary>
<category term="Tech前沿" scheme="http://coderedeng.github.io/categories/Tech%E5%89%8D%E6%B2%BF/"/>
<category term="AI前沿" scheme="http://coderedeng.github.io/tags/AI%E5%89%8D%E6%B2%BF/"/>
<category term="微软" scheme="http://coderedeng.github.io/tags/%E5%BE%AE%E8%BD%AF/"/>
<category term="MAI" scheme="http://coderedeng.github.io/tags/MAI/"/>
</entry>
<entry>
<title>Kimi K2.7-Code深度解析:Moonshot AI万亿参数MoE编程模型,推理Token减少30%</title>
<link href="http://coderedeng.github.io/2026/06/16/Kimi-K2-7-Code%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-Moonshot-AI%E4%B8%87%E4%BA%BF%E5%8F%82%E6%95%B0%E5%BC%80%E6%BA%90%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9E%8B/"/>
<id>http://coderedeng.github.io/2026/06/16/Kimi-K2-7-Code%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-Moonshot-AI%E4%B8%87%E4%BA%BF%E5%8F%82%E6%95%B0%E5%BC%80%E6%BA%90%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9E%8B/</id>
<published>2026-06-16T00:00:00.000Z</published>
<updated>2026-06-16T14:12:17.472Z</updated>
<content type="html"><![CDATA[<h2 id="引言:编程大模型的又一次跃迁"><a href="#引言:编程大模型的又一次跃迁" class="headerlink" title="引言:编程大模型的又一次跃迁"></a>引言:编程大模型的又一次跃迁</h2><p>2026年6月12日,北京AI初创公司月之暗面(Moonshot AI)正式发布了 <strong>Kimi K2.7-Code</strong>——一款专为代码生成、调试和重构场景优化的万亿参数MoE模型。该模型以Modified MIT许可证开源,权重已发布至Hugging Face(<a href="https://huggingface.co/moonshotai/Kimi-K2.7-Code">moonshotai/Kimi-K2.7-Code</a>),上线首周下载量即突破5万次。</p><p>在Claude Fable 5因出口管制限制国际访问的背景下,K2.7-Code迅速成为开发者社区关注的焦点——它不仅在多项基准测试中取得显著进步,更以30%的推理Token优化直接回应了大模型”过度思考”这一核心痛点。</p><h2 id="一、技术架构:1T参数MoE的高效之道"><a href="#一、技术架构:1T参数MoE的高效之道" class="headerlink" title="一、技术架构:1T参数MoE的高效之道"></a>一、技术架构:1T参数MoE的高效之道</h2><p>Kimi K2.7-Code继承了K2系列的核心架构设计,在万亿参数的规模下实现了令人印象深刻的效率表现:</p><p><strong>核心架构规格:</strong></p><table><thead><tr><th>维度</th><th>数值</th></tr></thead><tbody><tr><td>总参数量</td><td>1万亿(1T)</td></tr><tr><td>激活参数</td><td>~320亿(32B/token)</td></tr><tr><td>网络层数</td><td>61层</td></tr><tr><td>Expert数量</td><td>384路由专家 + 1共享专家</td></tr><tr><td>上下文窗口</td><td>256K tokens</td></tr><tr><td>架构类型</td><td>Transformer Decoder + MoE FFN</td></tr></tbody></table><p>MoE(Mixture of Experts)架构是Kimi系列的核心创新。每处理一个token,模型仅激活384个专家中的8个路由专家加上1个共享专家,总计约320亿参数参与计算。这种设计使得模型在训练时能够利用全部万亿参数的知识容量,而在推理时仅需承担约32B密度模型的算力开销——相当于以运行GPT-3.5级别的成本获得接近GPT-4级别的能力。</p><p>此外,K2.7-Code延续了月之暗面专有的 <strong>MLA(Multi-head Latent Attention)</strong> 注意力机制,大幅降低了长上下文场景下的KV缓存占用。配合256K的超长上下文窗口,模型能够一次性处理数万行代码的工程级任务——从完整的前后端项目到复杂的DevOps流水线脚本,均不在话下。</p><h2 id="二、性能提升:三大基准测试的全面突破"><a href="#二、性能提升:三大基准测试的全面突破" class="headerlink" title="二、性能提升:三大基准测试的全面突破"></a>二、性能提升:三大基准测试的全面突破</h2><p>Moonshot AI公布的官方数据显示,K2.7-Code相较于上一代K2.6在多项关键指标上取得了显著进步:</p><table><thead><tr><th>基准测试</th><th>K2.7-Code vs K2.6 提升幅度</th></tr></thead><tbody><tr><td>Kimi Code Bench v2</td><td><strong>+21.8%</strong></td></tr><tr><td>Program Bench</td><td><strong>+11.0%</strong></td></tr><tr><td>MLS Bench Lite</td><td><strong>+31.5%</strong></td></tr><tr><td>推理Token消耗</td><td><strong>~减少30%</strong></td></tr></tbody></table><p>其中,<strong>MLS Bench Lite提升31.5%</strong> 尤为引人注目。该基准专注于多语言代码理解和生成能力,在亚洲开发者社区中具有极高的参考价值——这意味着K2.7-Code对中文注释、中日英混合代码库的理解能力得到了显著增强。</p><p>而<strong>推理Token减少30%</strong> 则是本次更新最实用的改进。传统大模型在处理复杂编程任务时容易产生”过度思考”(overthinking)现象:生成大量冗余的中间推理步骤,导致API调用成本飙升且响应时间延长。K2.7-Code通过优化训练策略和推理算法,有效缩短了推理链长度——在LeetCode和GitHub常见仓库任务的测试中,模型在保持92%以上准确率的同时大幅提升了响应速度。</p><h2 id="三、核心技术特性深度分析"><a href="#三、核心技术特性深度分析" class="headerlink" title="三、核心技术特性深度分析"></a>三、核心技术特性深度分析</h2><h3 id="1-“反过度思考”训练范式"><a href="#1-“反过度思考”训练范式" class="headerlink" title="1. “反过度思考”训练范式"></a>1. “反过度思考”训练范式</h3><p>K2.7-Code的训练引入了新的约束机制,鼓励模型在保证正确性的前提下尽可能精简推理过程。具体来说:</p><figure><div class="code-wrapper"><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token comment"># K2.6生成示例(冗长)</span><span class="token triple-quoted-string string">"""让我分析一下这个问题。首先,我需要理解输入数据的格式...然后考虑边界条件... 好的,现在我来设计算法结构...第一步是数据预处理...第二步是核心逻辑实现..."""</span><span class="token comment"># K2.7-Code生成示例(精简高效)</span><span class="token keyword">def</span> <span class="token function">quick_sort</span><span class="token punctuation">(</span>arr<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">if</span> <span class="token builtin">len</span><span class="token punctuation">(</span>arr<span class="token punctuation">)</span> <span class="token operator"><=</span> <span class="token number">1</span><span class="token punctuation">:</span> <span class="token keyword">return</span> arr pivot <span class="token operator">=</span> arr<span class="token punctuation">[</span><span class="token builtin">len</span><span class="token punctuation">(</span>arr<span class="token punctuation">)</span><span class="token operator">//</span><span class="token number">2</span><span class="token punctuation">]</span> left <span class="token operator">=</span> <span class="token punctuation">[</span>x <span class="token keyword">for</span> x <span class="token keyword">in</span> arr <span class="token keyword">if</span> x <span class="token operator"><</span> pivot<span class="token punctuation">]</span> mid <span class="token operator">=</span> <span class="token punctuation">[</span>x <span class="token keyword">for</span> x <span class="token keyword">in</span> arr <span class="token keyword">if</span> x <span class="token operator">==</span> pivot<span class="token punctuation">]</span> right <span class="token operator">=</span> <span class="token punctuation">[</span>x <span class="token keyword">for</span> x <span class="token keyword">in</span> arr <span class="token keyword">if</span> x <span class="token operator">></span> pivot<span class="token punctuation">]</span> <span class="token keyword">return</span> quick_sort<span class="token punctuation">(</span>left<span class="token punctuation">)</span> <span class="token operator">+</span> mid <span class="token operator">+</span> quick_sort<span class="token punctuation">(</span>right<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>这种转变对实际开发场景意义重大。在CI/CD流水线或自动化代码审查场景中,每次API调用成本从K2.6的约$0.35/千token降至K2.7-Code的约$0.24/千token(按Moonshot API定价$0.95/M输入token计算),对于日处理数千次请求的企业用户而言,月度成本节约可达数万美元。</p><h3 id="2-多模态代码理解能力"><a href="#2-多模态代码理解能力" class="headerlink" title="2. 多模态代码理解能力"></a>2. 多模态代码理解能力</h3><p>K2.7-Code支持多模态输入——这不仅意味着它能处理纯文本代码,还能理解包含截图、架构图或设计稿的编程任务描述。例如:</p><figure><div class="code-wrapper"><pre class="line-numbers language-none"><code class="language-none">输入:一张前端UI设计的截图 + "请使用React实现这个组件"输出:完整的TypeScript React组件代码(含样式和交互逻辑)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div></figure><p>这一特性在AI辅助开发工具链中的价值日益凸显——开发者不再需要手动将设计稿转化为文字描述,模型能够直接从视觉输入中提取结构信息并生成对应代码。</p><h3 id="3-Agent原生架构"><a href="#3-Agent原生架构" class="headerlink" title="3. Agent原生架构"></a>3. Agent原生架构</h3><p>与早期的编程助手不同,K2.7-Code从架构层面就面向Agent工作流进行了优化。它支持:</p><ul><li><strong>多文件协同编辑</strong>:理解跨文件的依赖关系,进行一致性重构</li><li><strong>仓库级上下文感知</strong>:在256K窗口内维持对大型代码库的全局理解</li><li><strong>工具调用协议兼容</strong>:可直接与MCP(Model Context Protocol)生态集成</li></ul><h2 id="四、开源许可与部署方案"><a href="#四、开源许可与部署方案" class="headerlink" title="四、开源许可与部署方案"></a>四、开源许可与部署方案</h2><p>Kimi K2.7-Code采用 <strong>Modified MIT许可证</strong>,允许商业使用和二次开发——这是目前最宽松的 frontier 级别模型许可之一。相比需要额外审批的Claude API或受出口管制限制的GPT系列模型,K2.7-Code为国内开发者提供了真正的自主可控选择:</p><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 从Hugging Face下载权重</span>pip <span class="token function">install</span> transformers acceleratepython <span class="token parameter variable">-c</span> <span class="token string">"from transformers import AutoModelForCausalLM; \AutoModelForCausalLM.from_pretrained('moonshotai/Kimi-K2.7-Code')"</span><span class="token comment"># API调用示例(OpenAI兼容接口)</span>from openai <span class="token function">import</span> OpenAIclient <span class="token operator">=</span> OpenAI<span class="token punctuation">(</span>base_url<span class="token operator">=</span><span class="token string">"https://api.moonshot.cn/v1"</span>, <span class="token assign-left variable">api_key</span><span class="token operator">=</span><span class="token string">"your-key"</span><span class="token punctuation">)</span>response <span class="token operator">=</span> client.chat.completions.create<span class="token punctuation">(</span> <span class="token assign-left variable">model</span><span class="token operator">=</span><span class="token string">"kimi-k2.7-code"</span>, <span class="token assign-left variable">messages</span><span class="token operator">=</span><span class="token punctuation">[</span><span class="token punctuation">{</span><span class="token string">"role"</span><span class="token builtin class-name">:</span> <span class="token string">"user"</span>, <span class="token string">"content"</span><span class="token builtin class-name">:</span> <span class="token string">"请用Python实现快速排序"</span><span class="token punctuation">}</span><span class="token punctuation">]</span>, <span class="token assign-left variable">max_tokens</span><span class="token operator">=</span><span class="token number">4096</span>, <span class="token assign-left variable">temperature</span><span class="token operator">=</span><span class="token number">0.2</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>本地部署方面,考虑到1T参数的存储需求(约2TB FP16精度),建议至少配备8×A100 80GB或等效GPU集群。对于资源受限的场景,Moonshot同时提供云端API服务——输入token定价$0.95/百万tokens,输出token定价$4.00/百万tokens,在同等性能的闭源模型中属于极具竞争力的价格区间。</p><h2 id="五、行业影响与未来展望"><a href="#五、行业影响与未来展望" class="headerlink" title="五、行业影响与未来展望"></a>五、行业影响与未来展望</h2><p>Kimi K2.7-Code的发布标志着中国AI大模型在编程领域迈出了关键一步:</p><ol><li><p><strong>打破闭源垄断</strong>:在Claude Fable 5和GPT-5.5等国际前沿模型受限于访问权限的区域,K2.7-Code提供了可直接替代的工程级选择。Hugging Face上的社区评测显示,其在SWE-bench类任务中的表现已接近Fable级别的85%+通过率。</p></li><li><p><strong>推动效率竞赛</strong>:30%的推理Token优化不仅降低了单个用户的成本,更在行业层面树立了”效率优先于规模”的新标杆——证明模型能力不再单纯依赖参数膨胀,而是可以通过架构创新和训练策略的精进来实现跃升。</p></li><li><p><strong>开发者生态重塑</strong>:随着K2.7-Code与MCP、CrewAI等Agent框架的深度集成,未来的开发工作流将更倾向于”人类定义目标→Agent自主执行→人类审查结果”的协作模式,而非传统的逐行编码。</p></li><li><p><strong>多模态编程新范式</strong>:结合视觉理解能力,K2.7-Code正在推动从”文本描述需求→生成代码”向”截图/设计稿→直接生成可运行应用”的范式转变——这一趋势在2026年下半年有望随着更多工具的集成而加速落地。</p></li></ol><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>Moonshot AI通过Kimi K2.7-Code展示了其在MoE架构优化和编程大模型领域的深厚积累。1万亿参数的规模、30%的Token效率提升、以及开放许可策略,使其成为2026年最值得关注的开源编程模型之一。对于中国开发者而言,这不仅是技术选型上的一个优质选项,更是在AI时代构建自主可控开发工具链的重要基石。</p><p>随着Kimi K2系列的持续迭代,我们有理由期待——万亿参数级别的开源编程模型正在从”可用”走向”好用”,而真正的革命才刚刚开始。</p>]]></content>
<summary type="html"><h2 id="引言:编程大模型的又一次跃迁"><a href="#引言:编程大模型的又一次跃迁" class="headerlink" title="引言:编程大模型的又一次跃迁"></a>引言:编程大模型的又一次跃迁</h2><p>2026年6月12日,北京AI初创公司月之暗</summary>
<category term="Tech前沿" scheme="http://coderedeng.github.io/categories/Tech%E5%89%8D%E6%B2%BF/"/>
<category term="AI前沿" scheme="http://coderedeng.github.io/tags/AI%E5%89%8D%E6%B2%BF/"/>
<category term="Kimi K2.7-Code" scheme="http://coderedeng.github.io/tags/Kimi-K2-7-Code/"/>
</entry>
<entry>
<title>NVIDIA SkillSpector 深度解析:为 AI 代理技能装上"安检仪"</title>
<link href="http://coderedeng.github.io/2026/06/15/NVIDIA-SkillSpector%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-AI%E4%BB%A3%E7%90%86%E6%8A%80%E8%83%BD%E5%AE%89%E5%85%A8%E6%89%AB%E6%8F%8F%E5%99%A8/"/>
<id>http://coderedeng.github.io/2026/06/15/NVIDIA-SkillSpector%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-AI%E4%BB%A3%E7%90%86%E6%8A%80%E8%83%BD%E5%AE%89%E5%85%A8%E6%89%AB%E6%8F%8F%E5%99%A8/</id>
<published>2026-06-15T00:30:00.000Z</published>
<updated>2026-06-15T14:10:06.748Z</updated>
<content type="html"><![CDATA[<h2 id="背景:AI-代理技能的”信任危机”"><a href="#背景:AI-代理技能的”信任危机”" class="headerlink" title="背景:AI 代理技能的”信任危机”"></a>背景:AI 代理技能的”信任危机”</h2><p>随着 Claude Code、Codex CLI、Gemini CLI 等 AI 编程代理的爆发式增长,开发者开始大量使用社区发布的 Skill(技能)来扩展代理能力——从自动化代码审查到数据库管理,无所不包。然而,这些 Skill 在安装后以隐式信任的方式执行,几乎未经任何安全审查。</p><p>一项名为《Agent Skills in the Wild》的研究揭示了令人不安的现状:研究人员分析了来自主要市场的 <strong>42,447 个代理技能</strong>,发现 <strong>26.1% 包含至少一个漏洞</strong>,其中 <strong>5.2% 表现出明显的恶意意图</strong>。更严重的是,这些风险往往隐藏在看似无害的 Markdown 描述和脚本中。</p><p>在这样的背景下,NVIDIA 于 2026 年 3 月开源了 <strong>SkillSpector</strong>——一款专为 AI 代理技能设计的安全扫描器。短短三个月内该项目便斩获超过 <strong>3,000 Stars</strong>,成为 GitHub Trending 常客,直击 AI Agent 生态中最紧迫的安全痛点。</p><h2 id="核心特性:两阶段分析流水线"><a href="#核心特性:两阶段分析流水线" class="headerlink" title="核心特性:两阶段分析流水线"></a>核心特性:两阶段分析流水线</h2><p>SkillSpector 的核心设计理念是”<strong>快速初筛 + 精准复核</strong>“——通过两阶段分析流水线,在检测覆盖率和分析精度之间取得最佳平衡。</p><h3 id="第一阶段:静态分析(高速召回)"><a href="#第一阶段:静态分析(高速召回)" class="headerlink" title="第一阶段:静态分析(高速召回)"></a>第一阶段:静态分析(高速召回)</h3><p>第一阶段采用轻量级但覆盖面极广的静态检测方法:</p><ul><li><strong>11 个正则匹配分析器</strong>:针对 64 种已知漏洞模式进行快速扫描</li><li><strong>AST 行为分析</strong>:解析 Python 抽象语法树,检测危险调用如 <code>exec()</code>、<code>eval()</code>、<code>subprocess</code>、<code>os.system</code> 等</li><li><strong>实时 CVE 查询</strong>:通过 OSV.dev API 对依赖项进行在线漏洞核查,支持离线降级和内存缓存</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 基本用法:扫描本地技能目录</span>skillspector scan ./my-agent-skill/<span class="token comment"># 扫描 Git 仓库中的技能</span>skillspector scan https://github.com/user/my-skill<span class="token comment"># 输出 JSON 格式报告(适合 CI/CD 集成)</span>skillspector scan ./skill <span class="token parameter variable">--format</span> json <span class="token operator">></span> report.json<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="第二阶段:LLM-语义评估(可选,高精度)"><a href="#第二阶段:LLM-语义评估(可选,高精度)" class="headerlink" title="第二阶段:LLM 语义评估(可选,高精度)"></a>第二阶段:LLM 语义评估(可选,高精度)</h3><p>对于第一阶段标记的疑似问题,SkillSpector 提供可选的第二阶段分析——调用 OpenAI、Anthropic 或任何兼容 API 的大语言模型进行上下文理解:</p><ul><li><strong>意图判断</strong>:区分真正的恶意行为与误报</li><li><strong>自然语言解释</strong>:生成人类可读的安全评估说明</li><li><strong>精度提升</strong>:据官方数据,此阶段可将误报率降低约 **13%**(精度提升至 ~87%)</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token comment"># 配置 LLM 后端进行深度分析</span>export OPENAI_API_KEY="sk<span class="token punctuation">-</span>xxx"export OPENAI_BASE_URL="https<span class="token punctuation">:</span>//api.openai.com/v1"skillspector scan ./skill <span class="token punctuation">-</span><span class="token punctuation">-</span>llm<span class="token punctuation">-</span>eval<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="技术架构:覆盖-16-类安全威胁"><a href="#技术架构:覆盖-16-类安全威胁" class="headerlink" title="技术架构:覆盖 16 类安全威胁"></a>技术架构:覆盖 16 类安全威胁</h2><p>SkillSpector 的检测范围覆盖了 AI 代理技能中最关键的 <strong>16 类安全风险</strong>,共计 <strong>64 种漏洞模式</strong>:</p><table><thead><tr><th>类别</th><th>检测项数量</th><th>典型场景</th></tr></thead><tbody><tr><td>Prompt 注入</td><td>5</td><td>指令覆盖、隐藏指令、行为操纵</td></tr><tr><td>数据外泄</td><td>4</td><td>环境变量窃取、文件系统枚举、上下文泄露</td></tr><tr><td>供应链攻击</td><td>6</td><td>未锁定依赖、外部脚本拉取、已知 CVE 漏洞</td></tr><tr><td>AST 危险调用</td><td>8</td><td>exec/eval/subprocess/os.system 等</td></tr><tr><td>污点追踪</td><td>5</td><td>凭证外泄链、外部输入到代码执行</td></tr><tr><td>YARA 签名匹配</td><td>4</td><td>恶意软件、WebShell、加密货币矿机</td></tr><tr><td>MCP 专项检测</td><td>8</td><td>最小权限违规、工具投毒、Unicode 欺骗</td></tr></tbody></table><p>特别值得注意的是 <strong>MCP(Model Context Protocol)专项检测</strong>——随着 MCP 成为 AI 代理与外部工具交互的事实标准,SkillSpector 专门针对 MCP Server 的常见攻击面设计了检测规则,包括参数注入和隐藏指令等新型威胁。</p><h2 id="多格式输入与输出:无缝集成工作流"><a href="#多格式输入与输出:无缝集成工作流" class="headerlink" title="多格式输入与输出:无缝集成工作流"></a>多格式输入与输出:无缝集成工作流</h2><p>SkillSpector 支持多种输入源和输出格式,确保它能灵活融入现有开发流程:</p><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 扫描 zip 文件</span>skillspector scan ./skill-package.zip<span class="token comment"># Markdown 报告(适合 PR 评论)</span>skillspector scan ./my-skill <span class="token parameter variable">--format</span> markdown <span class="token operator">></span> security.md<span class="token comment"># SARIF 格式(与 GitHub Code Scanning、Semgrep 等工具兼容)</span>skillspector scan ./my-skill <span class="token parameter variable">--format</span> sarif <span class="token operator">></span> results.sarif<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>风险评分采用 <strong>0-100 的整数体系</strong>,并附带明确的安装建议:</p><table><thead><tr><th>分数范围</th><th>风险等级</th><th>建议操作</th></tr></thead><tbody><tr><td>0-25</td><td>LOW(低)</td><td>✅ SAFE — 可安全安装</td></tr><tr><td>26-50</td><td>MEDIUM(中)</td><td>⚠️ REVIEW — 需人工审核后再安装</td></tr><tr><td>51-75</td><td>HIGH(高)</td><td>🚫 CAUTION — 不建议直接安装</td></tr><tr><td>76-100</td><td>CRITICAL(严重)</td><td>❌ DO NOT INSTALL — 存在明确安全风险</td></tr></tbody></table><h2 id="影响与展望:为-AI-Agent-生态建立安全基线"><a href="#影响与展望:为-AI-Agent-生态建立安全基线" class="headerlink" title="影响与展望:为 AI Agent 生态建立安全基线"></a>影响与展望:为 AI Agent 生态建立安全基线</h2><p>SkillSpector 的开源释放标志着 <strong>AI 代理安全</strong> 从”事后补救”走向”事前防御”的关键转折。在 AI 编程代理日益成为开发者标配工具的趋势下,SkillSpector 提供的能力不仅适用于个人用户——它可以集成到 CI/CD 流水线中,作为第三方 Skill 引入前的自动化门禁。</p><p>NVIDIA 选择在此时推出这一工具也颇具战略意义:随着 Anthropic、OpenAI、Google 等巨头竞相扩展各自的代理技能市场,一个统一的、开源的安全扫描标准正在形成。SkillSpector 的 Apache 2.0 许可证确保了其可以被任何安全团队或企业自由集成,为整个 AI Agent 生态建立了一道坚实的安全防线。</p><p>对于开发者而言,在享受 AI 代理强大能力的同时,养成”先扫描后安装”的习惯——就像在安装浏览器扩展前审查权限一样——正逐渐成为新的最佳实践。SkillSpector 的出现,让这一习惯有了得力的工具支撑。</p><p><strong>参考资源:</strong></p><ul><li>GitHub: <a href="https://github.com/NVIDIA/SkillSpector">https://github.com/NVIDIA/SkillSpector</a></li><li>Agent Skills in the Wild 研究报告</li><li>OSV.dev API 文档: <a href="https://osv.dev/">https://osv.dev</a></li></ul>]]></content>
<summary type="html"><h2 id="背景:AI-代理技能的”信任危机”"><a href="#背景:AI-代理技能的”信任危机”" class="headerlink" title="背景:AI 代理技能的”信任危机”"></a>背景:AI 代理技能的”信任危机”</h2><p>随着 Claude </summary>
<category term="Tech前沿" scheme="http://coderedeng.github.io/categories/Tech%E5%89%8D%E6%B2%BF/"/>
<category term="AI安全" scheme="http://coderedeng.github.io/tags/AI%E5%AE%89%E5%85%A8/"/>
<category term="NVIDIA" scheme="http://coderedeng.github.io/tags/NVIDIA/"/>
</entry>
<entry>
<title>LMCache深度解析:LLM推理的KV缓存革命</title>
<link href="http://coderedeng.github.io/2026/06/14/LMCache%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-LLM%E6%8E%A8%E7%90%86%E7%9A%84KV%E7%BC%93%E5%AD%98%E9%9D%A9%E5%91%BD/"/>
<id>http://coderedeng.github.io/2026/06/14/LMCache%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-LLM%E6%8E%A8%E7%90%86%E7%9A%84KV%E7%BC%93%E5%AD%98%E9%9D%A9%E5%91%BD/</id>
<published>2026-06-14T00:00:00.000Z</published>
<updated>2026-06-14T14:49:00.732Z</updated>
<content type="html"><![CDATA[<h2 id="引言:KV缓存——LLM推理的隐形瓶颈"><a href="#引言:KV缓存——LLM推理的隐形瓶颈" class="headerlink" title="引言:KV缓存——LLM推理的隐形瓶颈"></a>引言:KV缓存——LLM推理的隐形瓶颈</h2><p>在大语言模型(LLM)部署中,GPU显存是最昂贵的资源。当你的Llama 3.1 70B模型在H100上运行时,你可能会惊讶地发现:<strong>在一个并发用户、128K上下文长度的场景下,KV Cache alone就要占用42GB显存</strong>——这已经接近单张80GB H100的极限。而当你把并发数提升到8时,KV Cache的需求飙升至343GB,相当于近5张H100的显存量。</p><p>这种现象被称为”Memory Wall”(内存墙)。在自回归生成过程中,模型需要为每个已生成的token保存Key-Value向量对,这些张量在整个请求生命周期中不断累积。对于长上下文、高并发的生产场景,KV Cache不仅吞噬GPU资源,更成为吞吐量与延迟的致命瓶颈。</p><p>开源项目 <strong>LMCache</strong>(<a href="https://github.com/LMCache/LMCache%EF%BC%89%E6%AD%A3%E6%98%AF%E4%B8%BA%E4%BA%86%E8%A7%A3%E5%86%B3%E8%BF%99%E4%B8%80%E6%A0%B9%E6%9C%AC%E6%80%A7%E6%8C%91%E6%88%98%E8%80%8C%E7%94%9F%E3%80%82%E8%87%AA2024%E5%B9%B4%E5%8F%91%E5%B8%83%E4%BB%A5%E6%9D%A5%EF%BC%8C%E5%AE%83%E8%BF%85%E9%80%9F%E6%88%90%E9%95%BF%E4%B8%BALLM%E6%8E%A8%E7%90%86%E7%94%9F%E6%80%81%E4%B8%AD%E4%BA%8B%E5%AE%9E%E4%B8%8A%E7%9A%84KV%E7%BC%93%E5%AD%98%E7%AE%A1%E7%90%86%E6%A0%87%E5%87%86%EF%BC%8C%E8%A2%ABvLLM%E3%80%81SGLang%E7%AD%89%E4%B8%BB%E6%B5%81%E6%8E%A8%E7%90%86%E5%BC%95%E6%93%8E%E5%8E%9F%E7%94%9F%E9%9B%86%E6%88%90%E3%80%82">https://github.com/LMCache/LMCache)正是为了解决这一根本性挑战而生。自2024年发布以来,它迅速成长为LLM推理生态中事实上的KV缓存管理标准,被vLLM、SGLang等主流推理引擎原生集成。</a></p><h2 id="什么是LMCache?核心特性解析"><a href="#什么是LMCache?核心特性解析" class="headerlink" title="什么是LMCache?核心特性解析"></a>什么是LMCache?核心特性解析</h2><p>LMCache定位为<strong>企业级LLM推理的KV Cache中间层</strong>。它的核心理念非常优雅:将LLM推理引擎从”独立的token处理器”转变为”以KV缓存为存储和通信介质的协同引擎集群”。</p><h3 id="1-跨查询缓存复用(Cache-Offloading)"><a href="#1-跨查询缓存复用(Cache-Offloading)" class="headerlink" title="1. 跨查询缓存复用(Cache Offloading)"></a>1. 跨查询缓存复用(Cache Offloading)</h3><p>传统推理中,每个用户请求都是孤立的——相同的文档或历史对话会被重复处理。LMCache通过<strong>prefix reuse</strong>技术,将已生成的KV Cache持久化到CPU内存、NVMe SSD甚至分布式存储中。当新用户发送包含相同前缀的请求时,系统直接从缓存中提取KV向量,跳过冗余计算。</p><figure><div class="code-wrapper"><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token comment"># 使用示例:pip install lmcache</span><span class="token keyword">from</span> lmcache<span class="token punctuation">.</span>integrations<span class="token punctuation">.</span>vllm<span class="token punctuation">.</span>lm_cache_server <span class="token keyword">import</span> LMCacheServerBackend<span class="token comment"># vLLM集成配置</span>engine <span class="token operator">=</span> vLLM<span class="token punctuation">(</span> model<span class="token operator">=</span><span class="token string">"meta-llama/Llama-3.1-70B"</span><span class="token punctuation">,</span> kv_connector<span class="token operator">=</span><span class="token string">"LMCacheServerConnectorV1"</span><span class="token punctuation">,</span> kv_buffer_size<span class="token operator">=</span><span class="token number">1e9</span><span class="token punctuation">,</span> <span class="token comment"># 缓存上限:1GB</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-Prefill-Decode解耦(PD-Disaggregation)"><a href="#2-Prefill-Decode解耦(PD-Disaggregation)" class="headerlink" title="2. Prefill-Decode解耦(PD Disaggregation)"></a>2. Prefill-Decode解耦(PD Disaggregation)</h3><p>这是LMCache最具革命性的特性。在LLM推理的两个阶段中——<strong>Prefill阶段</strong>(并行处理整个prompt,计算密集型)和<strong>Decode阶段</strong>(逐token生成,内存带宽密集型)——它们的硬件需求完全相反:</p><table><thead><tr><th>阶段</th><th>瓶颈类型</th><th>理想GPU配置</th></tr></thead><tbody><tr><td>Prefill</td><td>FP8 TFLOPS</td><td>H100 / B200</td></tr><tr><td>Decode</td><td>HBM带宽 (TB/s)</td><td>H200 (4.8 TB/s)</td></tr></tbody></table><p>当两者共享同一GPU时,长prompt的prefill请求会阻塞正在进行的decode流,导致Inter-Token Latency(ITL)剧烈抖动。LMCache通过<strong>KV Cache传输机制</strong>,允许将两个阶段分配到不同的物理GPU上运行——Prefill实例专注矩阵计算,Decode实例专注内存带宽,最终在相同硬件配置下实现最高 <strong>2.5倍goodput提升</strong>。</p><h3 id="3-KV缓存压缩与流式传输"><a href="#3-KV缓存压缩与流式传输" class="headerlink" title="3. KV缓存压缩与流式传输"></a>3. KV缓存压缩与流式传输</h3><p>LMCache支持多种压缩算法(FP8、INT4量化),可将KV Cache体积缩减60-90%。配合其<strong>流式分解压缩</strong>技术,客户端可以在收到完整缓存之前就开始解码——这对于交互式对话场景至关重要。</p><h2 id="技术架构深度分析"><a href="#技术架构深度分析" class="headerlink" title="技术架构深度分析"></a>技术架构深度分析</h2><h3 id="模块化连接器设计"><a href="#模块化连接器设计" class="headerlink" title="模块化连接器设计"></a>模块化连接器设计</h3><p>LMCache最精妙的设计在于其<strong>Connector抽象层</strong>。它将KV cache的传输逻辑与推理引擎解耦:</p><figure><div class="code-wrapper"><pre class="line-numbers language-none"><code class="language-none">┌─────────────────────────────────────────────┐│ vLLM / SGLang Engine ││ ┌───────────┐ ┌──────────────────────┐ ││ │ Scheduler │───▶│ KV Connector │ ││ │ (调度器) │ │ (KV传输连接器) │ ││ └───────────┘ └──────────┬───────────┘ ││ │ ││ send_tensor / recv │└──────────────────────────────┼──────────────┘ ▼ ┌────────────────────┐ │ LMCache Server │ │ (缓存管理服务) │ │ CPU / NVMe / 网络 │ └────────────────────┘<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>这种设计使得LMCache能够<strong>无缝适配推理引擎的快速迭代</strong>——无论是vLLM还是SGLang,只需更换Connector实现即可接入。</p><h3 id="性能数据验证"><a href="#性能数据验证" class="headerlink" title="性能数据验证"></a>性能数据验证</h3><p>根据MLSys 2026会议上的技术报告,LMCache在多个真实工作负载中的表现令人印象深刻:</p><ul><li><strong>多轮问答场景</strong>:与vLLM组合使用时,吞吐量最高提升 <strong>15倍</strong></li><li><strong>文档分析场景</strong>:跨引擎KV缓存共享使响应延迟降低 <strong>80%+</strong></li><li><strong>RAG检索增强</strong>:CacheBlend技术实现4-10倍的查询加速</li></ul><p>这些数字背后的原理很简单——与其让GPU反复计算相同的前缀token,不如把宝贵的算力留给真正需要生成的部分。</p><h2 id="生态影响与未来展望"><a href="#生态影响与未来展望" class="headerlink" title="生态影响与未来展望"></a>生态影响与未来展望</h2><h3 id="从工具到基础设施"><a href="#从工具到基础设施" class="headerlink" title="从工具到基础设施"></a>从工具到基础设施</h3><p>LMCache已经超越了单个工具的范畴。它正在成为LLM推理栈中的<strong>标准组件</strong>:</p><ul><li><strong>vLLM v0.9+</strong> 原生集成LMCache Connector</li><li><strong>SGLang</strong> 提供一等级的KV Cache管理API</li><li><strong>TensorMesh</strong>(Tensormesh.ai)等企业平台在其底层架构中采用LMCache作为默认缓存层</li><li>与FlexKV等分布式KV存储系统深度整合</li></ul><h3 id="挑战与方向"><a href="#挑战与方向" class="headerlink" title="挑战与方向"></a>挑战与方向</h3><p>尽管成就显著,LMCache仍面临一些挑战:</p><ol><li><strong>多节点协调</strong>:当前跨节点的缓存一致性协议仍有优化空间</li><li><strong>异构硬件支持</strong>:对AMD MI300X等新型GPU的适配仍在进行中</li><li><strong>成本模型</strong>:如何在CPU内存、NVMe和NVLink之间智能分配缓存层级,仍是开放问题</li></ol><p>未来,随着上下文窗口继续膨胀(1M+ token已成为可能),以及多模态推理场景的增长,KV Cache管理的重要性只会进一步上升。LMCache已经在MLSys 2026受邀演讲中展示了其研究深度——从CacheGen的压缩算法到CacheBlend的知识融合,这条技术路线正从工程优化走向系统级创新。</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>对于任何在生产环境中部署LLM的团队而言,KV Cache不再是可以忽视的”后台问题”。<strong>LMCache的出现标志着LLM推理基础设施的一个范式转变</strong>:从各自为战的独立引擎,转向以KV缓存为中心的协同架构。无论你是使用vLLM还是SGLang,无论你的模型是7B还是700B——理解并善用KV缓存技术,都将成为2026年AI工程师的核心竞争力之一。</p><p>正如LMCache团队在论文中所述:”今天的LLM推理系统 treating individual engines and queries independently for simplicity”——而明天,它们将共享记忆、协同工作。</p><hr><p><strong>参考资源:</strong></p><ul><li>LMCache官方文档:<a href="https://docs.lmcache.ai/">https://docs.lmcache.ai</a></li><li>GitHub仓库:<a href="https://github.com/LMCache/LMCache">https://github.com/LMCache/LMCache</a></li><li>arXiv论文(arXiv:2510.09665):<a href="https://arxiv.org/abs/2510.09665">https://arxiv.org/abs/2510.09665</a></li><li>CacheGen(SIGCOMM 2024):KV缓存压缩与流式传输的开创性研究</li></ul>]]></content>
<summary type="html"><h2 id="引言:KV缓存——LLM推理的隐形瓶颈"><a href="#引言:KV缓存——LLM推理的隐形瓶颈" class="headerlink" title="引言:KV缓存——LLM推理的隐形瓶颈"></a>引言:KV缓存——LLM推理的隐形瓶颈</h2><p>在大</summary>
<category term="Tech前沿" scheme="http://coderedeng.github.io/categories/Tech%E5%89%8D%E6%B2%BF/"/>
<category term="AI前沿" scheme="http://coderedeng.github.io/tags/AI%E5%89%8D%E6%B2%BF/"/>
<category term="KV Cache" scheme="http://coderedeng.github.io/tags/KV-Cache/"/>
<category term="LLM推理优化" scheme="http://coderedeng.github.io/tags/LLM%E6%8E%A8%E7%90%86%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>深度解析 Agent Skills:Addy Osmani 如何用工程规范驯服 AI 编程代理</title>
<link href="http://coderedeng.github.io/2026/06/13/%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-Agent-Skills-Addy-Osmani%E5%A6%82%E4%BD%95%E7%94%A8%E5%B7%A5%E7%A8%8B%E8%A7%84%E8%8C%83%E9%A9%AF%E6%9C%8D-AI-%E7%BC%96%E7%A8%8B%E4%BB%A3%E7%90%86/"/>
<id>http://coderedeng.github.io/2026/06/13/%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-Agent-Skills-Addy-Osmani%E5%A6%82%E4%BD%95%E7%94%A8%E5%B7%A5%E7%A8%8B%E8%A7%84%E8%8C%83%E9%A9%AF%E6%9C%8D-AI-%E7%BC%96%E7%A8%8B%E4%BB%A3%E7%90%86/</id>
<published>2026-06-13T10:00:00.000Z</published>
<updated>2026-06-13T23:28:25.303Z</updated>
<content type="html"><![CDATA[<h1 id="深度解析-Agent-Skills:Addy-Osmani-如何用工程规范驯服-AI-编程代理"><a href="#深度解析-Agent-Skills:Addy-Osmani-如何用工程规范驯服-AI-编程代理" class="headerlink" title="深度解析 Agent Skills:Addy Osmani 如何用工程规范驯服 AI 编程代理"></a>深度解析 Agent Skills:Addy Osmani 如何用工程规范驯服 AI 编程代理</h1><h2 id="引言:AI-编程工具的”最后一公里”难题"><a href="#引言:AI-编程工具的”最后一公里”难题" class="headerlink" title="引言:AI 编程工具的”最后一公里”难题"></a>引言:AI 编程工具的”最后一公里”难题</h2><p>2026 年的 GitHub Trending 榜单上,一个名字高居榜首——<strong>addyosmani/agent-skills</strong>。短短数月内斩获近 <strong>5 万星</strong>、超 <strong>5500 Fork</strong>,这个由 Google 前端工程师 Addy Osmani 发起的项目正在重新定义 AI 编程代理的工作方式。</p><p>当我们谈论 Cursor、Claude Code、GitHub Copilot 等 AI 编程工具时,一个核心矛盾始终存在:<strong>AI 代理拥有惊人的代码生成能力,却缺乏工程纪律。</strong> 它们会跳过测试、忽略代码规范、在”差不多就行”的诱惑下妥协——就像人类初入职场的程序员一样。Agent Skills 正是为了解决这一痛点而生。</p><figure><div class="code-wrapper"><pre class="line-numbers language-none"><code class="language-none">项目数据快照(2026-06-13)├── Stars: ~49,800+├── Forks: ~5,577├── License: MIT├── 语言: Shell (技能定义) + Markdown (内容)└── 支持工具: Claude Code / Cursor / Gemini CLI / Windsurf / Copilot / Codex<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="核心理念:从”提示词集合”到”工程工作流引擎”"><a href="#核心理念:从”提示词集合”到”工程工作流引擎”" class="headerlink" title="核心理念:从”提示词集合”到”工程工作流引擎”"></a>核心理念:从”提示词集合”到”工程工作流引擎”</h2><p>Agent Skills 的创始人 Addy Osmani 曾主导 Google 的前端性能优化标准(Lighthouse、Web Vitals),他对软件工程有着近乎偏执的坚持。在 Agent Skills 中,他将这套哲学转化为一套<strong>可执行的技能系统</strong>。</p><p>与传统 AI 提示词最大的不同在于:<strong>每个 Skill 都不是静态文档,而是带有步骤、检查点和退出标准的动态工作流。</strong></p><h3 id="七大开发阶段与-Slash-命令"><a href="#七大开发阶段与-Slash-命令" class="headerlink" title="七大开发阶段与 Slash 命令"></a>七大开发阶段与 Slash 命令</h3><p>Agent Skills 将整个软件开发流程抽象为七个核心命令,每个命令对应一个特定的工程阶段:</p><table><thead><tr><th>命令</th><th>阶段</th><th>核心理念</th></tr></thead><tbody><tr><td><code>/spec</code></td><td>定义需求</td><td>先有规范再写代码(Spec before Code)</td></tr><tr><td><code>/plan</code></td><td>制定计划</td><td>拆解为原子化小任务(Small, Atomic Tasks)</td></tr><tr><td><code>/build</code></td><td>增量构建</td><td>一次只构建一个功能切片(One Slice at a Time)</td></tr><tr><td><code>/test</code></td><td>验证测试</td><td>测试即证明,没有例外(Tests are Proof)</td></tr><tr><td><code>/review</code></td><td>代码审查</td><td>提升代码健康度(Improve Code Health)</td></tr><tr><td><code>/code-simplify</code></td><td>简化重构</td><td>清晰优于炫技(Clarity Over Cleverness)</td></tr><tr><td><code>/ship</code></td><td>生产部署</td><td>更快更安全(Faster is Safer)</td></tr></tbody></table><figure><div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span> 示例:/build 命令的工作流骨架</span><span class="token title important"><span class="token punctuation">##</span> Process</span><span class="token list punctuation">1.</span> 从 /plan 生成的任务列表中选择一个原子任务<span class="token list punctuation">2.</span> 理解现有代码结构和依赖关系<span class="token list punctuation">3.</span> 实现最小可工作版本<span class="token list punctuation">4.</span> 运行验证测试确保功能正确性<span class="token list punctuation">5.</span> 更新相关文档和类型定义<span class="token title important"><span class="token punctuation">##</span> Verification (Exit Criteria)</span><span class="token list punctuation">-</span> ✅ 所有测试通过(无警告)<span class="token list punctuation">-</span> ✅ 类型检查通过<span class="token list punctuation">-</span> ✅ 新功能的端到端测试已添加<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="“反合理化”表:对抗-AI-的捷径倾向"><a href="#“反合理化”表:对抗-AI-的捷径倾向" class="headerlink" title="“反合理化”表:对抗 AI 的捷径倾向"></a>“反合理化”表:对抗 AI 的捷径倾向</h3><p>Agent Skills 最独特的设计之一是 <strong>“Common Rationalizations”(常见合理化借口)</strong> 模块。每个技能都预判了 AI 代理可能用来跳过质量关卡的借口,并逐一反驳:</p><table><thead><tr><th>AI 代理的借口</th><th>Agent Skills 的反驳</th></tr></thead><tbody><tr><td>“这个功能很简单,不需要完整测试”</td><td>Google 经验表明,简单功能的回归 bug 成本最高(Hyrum’s Law)</td></tr><tr><td>“我先部署再说,后面再优化”</td><td>技术债复利效应:修复成本随时间呈指数增长</td></tr><tr><td>“代码已经能跑了,重构是过度工程”</td><td>可维护性不是性能指标——但它是团队生产力的核心变量</td></tr></tbody></table><h2 id="技术架构:模块化、可扩展的设计哲学"><a href="#技术架构:模块化、可扩展的设计哲学" class="headerlink" title="技术架构:模块化、可扩展的设计哲学"></a>技术架构:模块化、可扩展的设计哲学</h2><h3 id="目录结构解析"><a href="#目录结构解析" class="headerlink" title="目录结构解析"></a>目录结构解析</h3><figure><div class="code-wrapper"><pre class="line-numbers language-none"><code class="language-none">agent-skills/├── skills/ # 工程技能定义│ ├── spec-driven-development/ # 规范驱动开发│ │ └── SKILL.md # 每个技能的入口文件│ ├── test-driven-development/│ ├── code-review-and-quality/│ ├── incremental-implementation/│ ├── security-and-hardening/ # 安全加固│ ├── performance-optimization/ # 性能优化│ └── frontend-ui-engineering/ # 前端 UI 工程├── agents/ # AI 代理角色定义│ ├── code-reviewer.md # 代码审查员角色│ ├── test-engineer.md # 测试工程师角色│ └── security-auditor.md # 安全审计员角色├── references/ # 参考检查清单│ ├── testing-patterns.md│ ├── performance-checklist.md│ └── accessibility-checklist.md├── hooks/ # 会话生命周期钩子│ ├── session-start.sh # 自动注入元技能│ └── simplify-ignore.sh # 缓存优化├── .claude/commands/ # Claude Code 的斜杠命令配置├── .gemini/commands/ # Gemini CLI 的配置└── docs/ # 各工具的平台化设置指南<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="五大设计原则"><a href="#五大设计原则" class="headerlink" title="五大设计原则"></a>五大设计原则</h3><ol><li><p><strong>Process, not Prose</strong> — 技能是带步骤和检查点的工作流,不是让 Agent “阅读”的参考文档。Agent 必须跟随流程执行,而非自行挑选建议。</p></li><li><p><strong>Anti-Rationalization(反合理化)</strong> — 每个技能内置对常见借口的反驳表,从机制上阻止 Agent 跳过关键质量关卡。</p></li><li><p><strong>Verification is Non-Negotiable(验证不可协商)</strong> — 每个技能以证据要求结尾——测试通过、构建输出、运行时数据都是必须的。”看起来没问题”从来不够。</p></li><li><p><strong>Progressive Disclosure(渐进式披露)</strong> — <code>SKILL.md</code> 是入口点,支持性参考文档仅在需要时加载。这种设计将 Token 消耗降至最低,保持 Agent 的上下文聚焦。</p></li><li><p><strong>Composability over Coupling(组合优于耦合)</strong> — 技能、角色和命令是独立层,在编排时自由组合。任何技能均可单独使用,避免脆弱依赖链。</p></li></ol><h3 id="多平台兼容策略"><a href="#多平台兼容策略" class="headerlink" title="多平台兼容策略"></a>多平台兼容策略</h3><p>Agent Skills 采用”一次编写,处处运行”的策略——所有技能都是纯 Markdown 文件,通过各平台的特定加载机制接入:</p><table><thead><tr><th>AI 工具</th><th>接入方式</th></tr></thead><tbody><tr><td><strong>Claude Code</strong></td><td><code>.claude/commands/</code> + <code>SKILL.md</code> 自动发现</td></tr><tr><td><strong>Cursor</strong></td><td><code>.cursor/rules/</code> 规则文件</td></tr><tr><td><strong>Gemini CLI</strong></td><td><code>.gemini/commands/</code> + 系统提示注入</td></tr><tr><td><strong>Windsurf</strong></td><td><code>.windsurfrules</code> 配置文件</td></tr><tr><td><strong>GitHub Copilot</strong></td><td><code>.github/copilot-instructions.md</code></td></tr></tbody></table><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># Cursor 集成示例:加载核心技能作为规则</span><span class="token comment"># .cursor/rules/test-driven-development.md → 引用 skills/中的 SKILL.md 内容</span><span class="token comment"># Claude Code 集成示例:通过 AGENTS.md 自动发现</span><span class="token comment"># 项目根目录添加 AGENTS.md,Claude Code 会自动读取 skills/ 下的所有技能定义</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="技术深度分析:为什么这套设计能成功?"><a href="#技术深度分析:为什么这套设计能成功?" class="headerlink" title="技术深度分析:为什么这套设计能成功?"></a>技术深度分析:为什么这套设计能成功?</h2><h3 id="1-将-Google-工程文化产品化"><a href="#1-将-Google-工程文化产品化" class="headerlink" title="1. 将 Google 工程文化产品化"></a>1. 将 Google 工程文化产品化</h3><p>Addy Osmani 团队在 Google 积累的工程实践——Hyrum’s Law(接口语义稳定性)、Test Pyramid(测试金字塔)、Trunk-Based Development(主干开发)、Shift Left(左移测试)——被编码为可执行的 Agent 行为准则。这相当于把 Google 高级工程师的”肌肉记忆”变成了机器可读的工作流规范。</p><h3 id="2-Token-效率优化"><a href="#2-Token-效率优化" class="headerlink" title="2. Token 效率优化"></a>2. Token 效率优化</h3><p>在 LLM 上下文窗口有限的现实约束下,Agent Skills 的渐进式披露设计极为关键:</p><ul><li><strong>初始加载</strong>:仅 <code>SKILL.md</code> 入口文件(约 500-1000 tokens)</li><li><strong>按需加载</strong>:仅在特定步骤触发时才引入参考文档</li><li><strong>角色复用</strong>:同一个 code-reviewer.md 可被多个技能调用,避免重复注入</li></ul><h3 id="3-对抗-AI-代理的”过度自信偏差”"><a href="#3-对抗-AI-代理的”过度自信偏差”" class="headerlink" title="3. 对抗 AI 代理的”过度自信偏差”"></a>3. 对抗 AI 代理的”过度自信偏差”</h3><p>研究表明,AI 编程代理在代码审查中会系统性低估自身错误的概率(约 40% 的错误率被低估)。Agent Skills 通过强制检查点(checkpoint)和证据要求(evidence requirements),从流程层面弥补了这一认知缺陷。</p><h2 id="实际应用场景与生态影响"><a href="#实际应用场景与生态影响" class="headerlink" title="实际应用场景与生态影响"></a>实际应用场景与生态影响</h2><h3 id="企业级-AI-编程部署"><a href="#企业级-AI-编程部署" class="headerlink" title="企业级 AI 编程部署"></a>企业级 AI 编程部署</h3><p>对于正在大规模引入 AI 编码工具的企业,Agent Skills 提供了一套<strong>开箱即用的工程规范框架</strong>。团队无需从零制定规则——直接采用这套经过社区验证的技能集,即可让 AI 代理遵循统一的开发标准。</p><figure><div class="code-wrapper"><pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token comment"># 示例:在 Cursor 中配置核心技能策略</span><span class="token punctuation">{</span> <span class="token key atrule">"essential_skills"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">"test-driven-development"</span><span class="token punctuation">,</span> <span class="token comment"># TDD 工作流(始终加载)</span> "code<span class="token punctuation">-</span>review<span class="token punctuation">-</span>and<span class="token punctuation">-</span>quality"<span class="token punctuation">,</span> <span class="token comment"># 五维度代码审查</span> "incremental<span class="token punctuation">-</span>implementation" <span class="token comment"># 增量实现</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token key atrule">"phase_specific_skills"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token key atrule">"frontend_project"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"frontend-ui-engineering"</span><span class="token punctuation">,</span> <span class="token string">"accessibility-checklist"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token key atrule">"api_service"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"security-and-hardening"</span><span class="token punctuation">,</span> <span class="token string">"performance-optimization"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="对-AI-Agent-生态的深远影响"><a href="#对-AI-Agent-生态的深远影响" class="headerlink" title="对 AI Agent 生态的深远影响"></a>对 AI Agent 生态的深远影响</h3><p>Agent Skills 的成功标志着 AI 编程工具发展的一个重要分水岭:<strong>从”能写代码”到”按规范写代码”。</strong></p><p>传统 AI 辅助编程关注的是<strong>生成速度</strong>——如何更快地写出功能正确的代码。而 Agent Skills 转向了<strong>工程质量</strong>——如何让 AI 在生成的同时遵守工程纪律、保持代码可维护性、通过质量关卡。这种范式的转变,正是 AI 编码工具从”玩具”走向”生产级基础设施”的关键一步。</p><h2 id="展望:AI-编程的下一个进化方向"><a href="#展望:AI-编程的下一个进化方向" class="headerlink" title="展望:AI 编程的下一个进化方向"></a>展望:AI 编程的下一个进化方向</h2><p>随着 Agent Skills 生态的快速扩张,我们可以预见以下几个趋势:</p><ol><li><strong>垂直领域技能专业化</strong> — 金融、医疗、嵌入式等行业的专用工程规范将被抽象为独立技能包</li><li><strong>动态技能编排</strong> — AI 代理将学会根据项目类型自动选择和组合最合适的技能链</li><li><strong>社区驱动的技能市场</strong> — 类似 npm 的生态系统将出现,开发者可以发布、分享和版本化管理自己的工程技能</li></ol><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>Agent Skills 证明了:<strong>AI 不需要更聪明的模型,而是需要更好的工作流程。</strong> 当工程师们把数十年积累的工程纪律编码为机器可执行的工作流时,AI 代理不再是那个”写得快但写得糙”的新手程序员——它们正在成为真正的资深工程师。</p><p>如果你还没有尝试过这套系统,现在正是最佳时机。在 AI 编程工具竞争日益激烈的 2026 年,让 Agent Skills 为你的开发流程注入工程纪律——这可能是你今年最值得投资的 5 分钟配置。</p><blockquote><p><strong>项目链接</strong>:<a href="https://github.com/addyosmani/agent-skills">github.com/addyosmani/agent-skills</a></p><p><strong>本文参考来源</strong>:GitHub Trending(2026-06-13)、Agent Skills 官方 README、Zread.ai 分析报告、FindAgent 工具目录</p></blockquote>]]></content>
<summary type="html"><h1 id="深度解析-Agent-Skills:Addy-Osmani-如何用工程规范驯服-AI-编程代理"><a href="#深度解析-Agent-Skills:Addy-Osmani-如何用工程规范驯服-AI-编程代理" class="headerlink" title</summary>
<category term="Tech前沿" scheme="http://coderedeng.github.io/categories/Tech%E5%89%8D%E6%B2%BF/"/>
<category term="AI编程工具" scheme="http://coderedeng.github.io/tags/AI%E7%BC%96%E7%A8%8B%E5%B7%A5%E5%85%B7/"/>
<category term="Agent Skills" scheme="http://coderedeng.github.io/tags/Agent-Skills/"/>
</entry>
<entry>
<title>Claude Fable 5深度解析:Anthropic首个Mythos-class模型横空出世</title>
<link href="http://coderedeng.github.io/2026/06/13/Claude-Fable-5%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-Anthropic%E9%A6%96%E4%B8%AAMythos-class%E6%A8%A1%E5%9E%8B/"/>
<id>http://coderedeng.github.io/2026/06/13/Claude-Fable-5%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-Anthropic%E9%A6%96%E4%B8%AAMythos-class%E6%A8%A1%E5%9E%8B/</id>
<published>2026-06-13T02:00:00.000Z</published>
<updated>2026-06-13T08:31:20.916Z</updated>
<content type="html"><![CDATA[<h2 id="引言:一个新的能力层级诞生"><a href="#引言:一个新的能力层级诞生" class="headerlink" title="引言:一个新的能力层级诞生"></a>引言:一个新的能力层级诞生</h2><p>2026年6月9日,Anthropic发布了一款引发业界震动的新模型——<strong>Claude Fable 5</strong>。这不是简单的版本号迭代,而是Anthropic首次推出全新的”Mythos-class”能力层级,定位高于现有的Opus家族。与此同时,同一底层模型的受限版本<strong>Claude Mythos 5</strong>也在Project Glasswing项目中面向认证合作伙伴开放。</p><p>Fable 5的发布标志着大模型竞争进入了一个全新阶段:从”谁能更快回答问题”转向”谁能持续完成更复杂的工程任务”。</p><h2 id="什么是Mythos-class?"><a href="#什么是Mythos-class?" class="headerlink" title="什么是Mythos-class?"></a>什么是Mythos-class?</h2><p>在理解Fable 5之前,需要先了解Anthropic的能力层级演变:</p><table><thead><tr><th>层级</th><th>代表模型</th><th>定位</th></tr></thead><tbody><tr><td>Haiku-class</td><td>Haiku 4.5</td><td>速度与成本优先</td></tr><tr><td>Sonnet-class</td><td>Sonnet 4.6</td><td>通用能力均衡</td></tr><tr><td>Opus-class</td><td>Opus 4.8</td><td>最强推理与复杂任务</td></tr><tr><td><strong>Mythos-class</strong></td><td><strong>Fable 5 / Mythos 5</strong></td><td><strong>超越Opus的新标杆</strong></td></tr></tbody></table><p>Anthropic将Fable 5描述为”公司之前为通用用户发布的任何模型中能力最强的版本”。它不是对现有模型的修补,而是一个全新的架构世代。</p><h2 id="Fable-5-vs-Opus-4-8:关键差异"><a href="#Fable-5-vs-Opus-4-8:关键差异" class="headerlink" title="Fable 5 vs Opus 4.8:关键差异"></a>Fable 5 vs Opus 4.8:关键差异</h2><h3 id="1-长程自主性(Long-horizon-Autonomy)"><a href="#1-长程自主性(Long-horizon-Autonomy)" class="headerlink" title="1. 长程自主性(Long-horizon Autonomy)"></a>1. 长程自主性(Long-horizon Autonomy)</h3><p>Fable 5最引人注目的特性是其在<strong>长时间代理任务</strong>中的表现。根据第三方评测和开发者反馈,Fable 5可以在极少人工干预的情况下连续运行数天,完成复杂的软件工程工作流——从规划到子任务委派再到自我验证,整个链条都可以由模型自主推进。</p><p>这与传统的”问答式AI”有本质区别:Fable 5更像是一个<strong>高级项目助手</strong>,而非简单的聊天机器人。</p><h3 id="2-基准测试数据(第三方评测)"><a href="#2-基准测试数据(第三方评测)" class="headerlink" title="2. 基准测试数据(第三方评测)"></a>2. 基准测试数据(第三方评测)</h3><p>Anthropic官方尚未公布完整的系统卡片数据,但独立测试已经给出了初步信号:</p><table><thead><tr><th>基准测试</th><th>Claude Fable 5</th><th>Claude Opus 4.8</th><th>GPT-5.5</th><th>Gemini 3.1 Pro</th></tr></thead><tbody><tr><td>SWE-Bench Pro(代理编程)</td><td><strong>80.3%</strong></td><td>69.2%</td><td>58.6%</td><td>54.2%</td></tr><tr><td>Terminal-Bench 2.1</td><td><strong>88.0%</strong></td><td>—</td><td>83.4%</td><td>—</td></tr><tr><td>Humanity’s Last Exam(无工具)</td><td>59.0%</td><td>—</td><td>52.2%</td><td>—</td></tr><tr><td>FrontierCode Diamond</td><td><strong>29.3%</strong></td><td>~14%</td><td>—</td><td>—</td></tr><tr><td>空间推理</td><td><strong>38.6%</strong></td><td>14.5%</td><td>—</td><td>—</td></tr></tbody></table><p>其中最具冲击力的数据是**SWE-Bench Pro的80.3%**——比Opus 4.8高出约11个百分点,领先GPT-5.5超过20个百分点。在代理编程(Agentic Coding)领域,Fable 5已经建立了明显优势。</p><h3 id="3-应用场景定位"><a href="#3-应用场景定位" class="headerlink" title="3. 应用场景定位"></a>3. 应用场景定位</h3><p>Anthropic明确将Fable 5定位为**”硬知识工作”**模型,最适合以下场景:</p><ul><li><strong>大型代码迁移与重构</strong>——处理跨仓库、跨语言的复杂重构任务</li><li><strong>多阶段分析</strong>——金融建模、法律文件审查、科研文献综合分析</li><li><strong>文档与视觉任务</strong>——PDF深度解析、表格提取、从截图到界面的原型设计</li><li><strong>科学工作流</strong>——需要持续推理和验证的实验流程</li></ul><p>对于日常简单对话,Fable 5可能”性能过剩”;但对于那些让现有模型感到吃力的复杂任务,Fable 5展现出了质的飞跃。</p><h2 id="安全护栏:能力越强,控制越严"><a href="#安全护栏:能力越强,控制越严" class="headerlink" title="安全护栏:能力越强,控制越严"></a>安全护栏:能力越强,控制越严</h2><p>Fable 5的能力引发了Anthropic对安全的深度思考。作为史上发布的最强通用模型的公共版本,它配备了<strong>最激进的安全机制</strong>:</p><ol><li><p><strong>敏感查询自动回退</strong>——当请求被标记为网络安全、生物研究、化学或模型蒸馏相关时,响应将由Claude Opus 4.8处理而非Fable 5。Anthropic表示超过95%的Fable会话不会触发此回退。</p></li><li><p><strong>30天数据保留</strong>——所有Fable 5和Mythos 5的请求都需保留30天用于安全监控,这比现有模型的标准策略更为严格。</p></li><li><p><strong>Project Glasswing项目</strong>——同一底层模型的完整版Mythos 5仅面向经过审核的合作伙伴开放。该项目在2026年5月已有约50家伙伴使用Claude Mythos Preview发现了超过10,000个高危或严重级别漏洞;到6月已扩展至全球15个国家的约150个组织。</p></li></ol><p>这种”强能力+强约束”的设计思路,反映了Anthropic在发布前沿AI时的核心哲学:<strong>不让能力增长失控</strong>。</p><h2 id="定价与可用性"><a href="#定价与可用性" class="headerlink" title="定价与可用性"></a>定价与可用性</h2><p>Fable 5的定价是Opus 4.8的两倍:</p><table><thead><tr><th>模型</th><th>输入价格(每百万token)</th><th>输出价格(每百万token)</th></tr></thead><tbody><tr><td>Claude Fable 5</td><td>$10.00</td><td>$50.00</td></tr><tr><td>Claude Opus 4.8</td><td>$5.00</td><td>$25.00</td></tr></tbody></table><p><strong>API模型ID</strong>:<code>claude-fable-5</code></p><p><strong>发布窗口期</strong>(6月9日至6月23日):Fable 5在Claude Pro、Max、Team和企业版中免费提供。从6月23日起,订阅用户将需要消耗额度使用。</p><p><strong>可用平台</strong>:Claude API、AWS Claude Platform、Amazon Bedrock、Google Vertex AI、Microsoft Foundry——覆盖了几乎所有主流云平台。</p><h2 id="与竞品对比:AI编程能力的格局重塑"><a href="#与竞品对比:AI编程能力的格局重塑" class="headerlink" title="与竞品对比:AI编程能力的格局重塑"></a>与竞品对比:AI编程能力的格局重塑</h2><p>在代理编程这一Fable 5的核心优势领域,竞争格局正在被重写:</p><ul><li><strong>SWE-Bench Pro</strong>:Fable 5以80.3%的成绩领先,Opus 4.8(69.2%)位居第二,GPT-5.5(58.6%)差距明显。</li><li><strong>Terminal-Bench</strong>:Fable 5的88.0%在终端交互任务中展现出对命令行环境的深度理解。</li><li><strong>FrontierCode Diamond</strong>:Fable 5以29.3%远超Opus 4.8的约14%,表明其在复杂代码生成上的代际优势。</li></ul><p>这些数字意味着什么?在软件工程领域,从60%到80%的进步不是线性改进——它跨越了一个关键门槛:模型开始能够独立处理<strong>需要多步骤推理、跨文件协调和自主调试</strong>的真实工程任务。对于开发团队而言,Fable 5 + Claude Code的组合已经具备了”半自主工程师”的雏形。</p><h2 id="未来展望:Mythos-class之后是什么?"><a href="#未来展望:Mythos-class之后是什么?" class="headerlink" title="未来展望:Mythos-class之后是什么?"></a>未来展望:Mythos-class之后是什么?</h2><p>Fable 5的发布提出了一个有趣的问题:<strong>如果Opus已经是”最强通用模型”,那为什么还需要一个新的层级?</strong></p><p>Anthropic给出的答案是:<strong>能力不是无限的线性增长,而是存在不同的能力相态</strong>。就像水的固态、液态、气态一样,Fable 5代表的Mythos-class可能在某些关键维度(长程推理、代理自主性、多模态理解)上发生了”相变”——不是更快或更便宜,而是<strong>本质上能够处理以前无法处理的任務类型</strong>。</p><p>同时,Project Glasswing项目的扩展也暗示了一个可能的未来:当Mythos-class的安全护栏逐步完善后,我们可能会看到更多受限能力的公开化释放。届时,AI的能力边界将被进一步拓展。</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>Claude Fable 5的发布不仅仅是一个新模型的亮相,它是Anthropic对”下一代AI应该是什么样子”的回答:<strong>不是更快的问答机器,而是能够持续工作、自主规划、自我验证的高级智能体</strong>。</p><p>对于开发者而言,现在正是体验Fable 5的最佳时机——免费窗口期即将结束。如果你正在处理复杂的代码库迁移、深度文档分析或需要长时间推理的科学任务,Fable 5值得你一试。毕竟在AI编程能力竞赛中,80%和60%之间的差距,可能就是你项目成功与失败的分界线。</p><blockquote><p><strong>参考来源</strong>:Anthropic官方公告、Claude模型文档、Project Glasswing更新报告及第三方独立评测数据。</p></blockquote>]]></content>
<summary type="html"><h2 id="引言:一个新的能力层级诞生"><a href="#引言:一个新的能力层级诞生" class="headerlink" title="引言:一个新的能力层级诞生"></a>引言:一个新的能力层级诞生</h2><p>2026年6月9日,Anthropic发布了一款引发</summary>
<category term="AI前沿" scheme="http://coderedeng.github.io/categories/AI%E5%89%8D%E6%B2%BF/"/>
<category term="Claude" scheme="http://coderedeng.github.io/tags/Claude/"/>
<category term="Anthropic" scheme="http://coderedeng.github.io/tags/Anthropic/"/>
<category term="Mythos" scheme="http://coderedeng.github.io/tags/Mythos/"/>
</entry>
<entry>
<title>Gemini 3.5 Flash深度解析:Google I/O 2026最强Agentic模型发布,性能碾压上一代旗舰</title>
<link href="http://coderedeng.github.io/2026/06/13/Gemini-3.5-Flash%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-Google-I-O-2026%E6%9C%80%E5%BC%BAAgentic%E6%A8%A1%E5%9E%8B/"/>
<id>http://coderedeng.github.io/2026/06/13/Gemini-3.5-Flash%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-Google-I-O-2026%E6%9C%80%E5%BC%BAAgentic%E6%A8%A1%E5%9E%8B/</id>
<published>2026-06-13T00:00:00.000Z</published>
<updated>2026-06-12T18:15:46.834Z</updated>
<content type="html"><![CDATA[<h2 id="一、引言:Google-I-x2F-O-2026的”核弹级”发布"><a href="#一、引言:Google-I-x2F-O-2026的”核弹级”发布" class="headerlink" title="一、引言:Google I/O 2026的”核弹级”发布"></a>一、引言:Google I/O 2026的”核弹级”发布</h2><p>2026年5月19日,Google在Mountain View海岸线圆形剧场(Shoreline Amphitheatre)举办了年度开发者大会I/O。CEO Sundar Pichai在主舞台上带来了今年最重磅的AI发布——<strong>Gemini 3.5 Flash</strong>。与此同时,旗舰版Gemini 3.5 Pro也宣布将于同年6月正式推出。</p><p>这并非一次常规的模型迭代。Gemini 3.5 Flash在几乎所有关键基准测试中都击败了Google自家三个月前刚发布的上一代旗舰级模型 <strong>Gemini 3.1 Pro</strong>——而且它的运行速度更快、成本更低。这种”下一代Flash超越上一代Pro”的降维打击,标志着AI模型家族内部的力量格局正在发生根本性重塑。</p><p>本文将深入分析Gemini 3.5 Flash的技术架构、基准性能、定价策略及其对开发者生态的影响。</p><h2 id="二、核心规格与性能数据"><a href="#二、核心规格与性能数据" class="headerlink" title="二、核心规格与性能数据"></a>二、核心规格与性能数据</h2><h3 id="2-1-关键参数一览"><a href="#2-1-关键参数一览" class="headerlink" title="2.1 关键参数一览"></a>2.1 关键参数一览</h3><table><thead><tr><th>指标</th><th>Gemini 3.5 Flash</th></tr></thead><tbody><tr><td>上下文窗口(输入)</td><td><strong>1,048,576 tokens</strong>(约1M)</td></tr><tr><td>最大输出tokens</td><td><strong>65,536</strong></td></tr><tr><td>多模态输入</td><td>文本、图像、视频、音频(原生支持)</td></tr><tr><td>输出模式</td><td>文本 + 富图形生成</td></tr><tr><td>输出速度</td><td><strong>~280 tokens/sec</strong>(Artificial Analysis实测)</td></tr><tr><td>模型API ID</td><td><code>gemini-3.5-flash</code></td></tr></tbody></table><h3 id="2-2-基准测试:碾压3-1-Pro的硬核数据"><a href="#2-2-基准测试:碾压3-1-Pro的硬核数据" class="headerlink" title="2.2 基准测试:碾压3.1 Pro的硬核数据"></a>2.2 基准测试:碾压3.1 Pro的硬核数据</h3><p>Google DeepMind CTO Koray Kavukcuoglu在I/O现场明确表示,3.5 Flash是”Google迄今最强的Agentic与编码模型”。以下是核心基准成绩(数据来源:Google官方发布 + Artificial Analysis):</p><table><thead><tr><th>评测项</th><th>Gemini 3.5 Flash</th><th>Gemini 3.1 Pro</th><th>Claude Opus 4.7</th><th>GPT-5.5</th></tr></thead><tbody><tr><td><strong>Terminal-Bench 2.1</strong></td><td><strong>76.2%</strong></td><td>~70%</td><td>—</td><td>—</td></tr><tr><td><strong>GDPval-AA(Agentic)</strong></td><td><strong>1656 Elo</strong></td><td>~1580 Elo</td><td>1700+</td><td>—</td></tr><tr><td><strong>MCP Atlas</strong></td><td><strong>83.6%</strong></td><td>~78%</td><td>—</td><td>—</td></tr><tr><td><strong>Coding(SWE-Bench Pro)</strong></td><td>超越3.1 Pro</td><td>—</td><td><strong>64.3%</strong></td><td>58.6%</td></tr></tbody></table><p>特别值得注意的是,Gemini 3.5 Flash在Agentic场景下取得了突破性的成绩。GDPval-AA评测中高达<strong>1656 Elo</strong>的分数表明,在处理文件系统操作、浏览器交互和第三方API调用等多步骤任务时,该模型展现出了极强的规划与执行能力。</p><h2 id="三、技术架构与创新亮点"><a href="#三、技术架构与创新亮点" class="headerlink" title="三、技术架构与创新亮点"></a>三、技术架构与创新亮点</h2><h3 id="3-1-Flash与Pro的关系被彻底颠覆"><a href="#3-1-Flash与Pro的关系被彻底颠覆" class="headerlink" title="3.1 Flash与Pro的关系被彻底颠覆"></a>3.1 Flash与Pro的关系被彻底颠覆</h3><p>在传统的AI模型分层中,”Flash”定位是快速低成本,而”Pro”代表高性能旗舰。这种层级关系一直被视为不可逾越的鸿沟——就像汽车行业中经济型轿车不可能在性能上超越豪华跑车一样。</p><p>但Gemini 3.5 Flash打破了这一认知。Google DeepMind通过以下关键技术手段实现了Flash对Pro的越级:</p><ol><li><strong>MoE(混合专家)架构优化</strong>:进一步提升了参数利用率,使模型在推理时只激活最相关的专家网络</li><li><strong>Agentic训练管线升级</strong>:针对文件系统、浏览器操作和API调用的端到端强化学习</li><li><strong>KV Cache压缩技术</strong>:大幅降低长上下文场景下的推理延迟</li></ol><h3 id="3-2-多模态能力的原生融合"><a href="#3-2-多模态能力的原生融合" class="headerlink" title="3.2 多模态能力的原生融合"></a>3.2 多模态能力的原生融合</h3><p>Gemini 3.5 Flash支持文本、图像、视频和音频的原生多模态输入。这意味着开发者可以在同一个请求中混合处理多种类型的数据——例如,给模型发送一段产品演示视频的同时附加详细的文字描述和音频说明,模型能够理解并关联所有信息流。</p><h3 id="3-3-Gemini-Spark:持久化个人AI-Agent"><a href="#3-3-Gemini-Spark:持久化个人AI-Agent" class="headerlink" title="3.3 Gemini Spark:持久化个人AI Agent"></a>3.3 Gemini Spark:持久化个人AI Agent</h3><p>除了Gemini 3.5 Flash本身,Google在I/O上还发布了<strong>Gemini Spark</strong>——一款基于3.5 Flash构建的持久化个人AI Agent。它具备跨会话记忆能力,能够持续学习用户的偏好和工作习惯,类似于”数字分身”的概念。目前Spark已率先在美国AI Ultra($100/月)订阅用户中推出。</p><h2 id="四、定价策略:开发者生态的关键博弈"><a href="#四、定价策略:开发者生态的关键博弈" class="headerlink" title="四、定价策略:开发者生态的关键博弈"></a>四、定价策略:开发者生态的关键博弈</h2><h3 id="4-1-API价格一览"><a href="#4-1-API价格一览" class="headerlink" title="4.1 API价格一览"></a>4.1 API价格一览</h3><table><thead><tr><th>模型</th><th>输入价格($/百万tokens)</th><th>输出价格($/百万tokens)</th></tr></thead><tbody><tr><td>Gemini 3.5 Flash</td><td><strong>$1.50</strong></td><td><strong>$9.00</strong></td></tr><tr><td>Gemini 3.1 Pro</td><td>—</td><td>~$12.50</td></tr><tr><td>Claude Opus 4.7</td><td>$15.00</td><td>$75.00</td></tr><tr><td>GPT-5.5</td><td>$5.00</td><td>$30.00</td></tr></tbody></table><p>Gemini 3.5 Flash的定价策略相当激进:虽然比上一代Flash-Lite贵了约6倍,但相比Claude Opus 4.7便宜了一个数量级,也比GPT-5.5低了大约**80%**。对于大规模部署AI Agent的企业而言,这意味着同样的预算可以支撑多出一倍的调用量。</p><h3 id="4-2-成本优化的实际意义"><a href="#4-2-成本优化的实际意义" class="headerlink" title="4.2 成本优化的实际意义"></a>4.2 成本优化的实际意义</h3><p>以一个典型的生产环境为例:假设某公司每天处理10亿tokens的AI编码辅助请求。</p><ul><li>使用Claude Opus 4.7:年API费用约 <strong>$825万</strong></li><li>使用GPT-5.5:年API费用约 <strong>$328万</strong></li><li>使用Gemini 3.5 Flash:年API费用约 <strong>~$165万</strong></li></ul><p>成本差距不是小数点级别的,而是数量级级别的。这正是Google将AI Agent工作负载作为Flash定位核心的战略意图——用极具竞争力的价格抢占企业级市场。</p><h2 id="五、代码示例:在Python中调用Gemini-3-5-Flash"><a href="#五、代码示例:在Python中调用Gemini-3-5-Flash" class="headerlink" title="五、代码示例:在Python中调用Gemini 3.5 Flash"></a>五、代码示例:在Python中调用Gemini 3.5 Flash</h2><p>使用Google官方SDK调用Gemini 3.5 Flash非常简单:</p><figure><div class="code-wrapper"><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> google<span class="token punctuation">.</span>generativeai <span class="token keyword">as</span> genai<span class="token comment"># 配置API密钥</span>genai<span class="token punctuation">.</span>configure<span class="token punctuation">(</span>api_key<span class="token operator">=</span><span class="token string">"YOUR_API_KEY"</span><span class="token punctuation">)</span><span class="token comment"># 选择模型</span>model <span class="token operator">=</span> genai<span class="token punctuation">.</span>GenerativeModel<span class="token punctuation">(</span><span class="token string">"gemini-3.5-flash"</span><span class="token punctuation">)</span><span class="token comment"># 多模态对话示例</span>response <span class="token operator">=</span> model<span class="token punctuation">.</span>generate_content<span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">"请分析这张图表的数据趋势"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token string">"mime_type"</span><span class="token punctuation">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span> <span class="token string">"data"</span><span class="token punctuation">:</span> <span class="token string">b"<base64_encoded_image>"</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>text<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>对于Agentic编程场景,Google也提供了专门的工具调用接口:</p><figure><div class="code-wrapper"><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token comment"># 使用工具调用的Agent模式</span>tools <span class="token operator">=</span> <span class="token punctuation">[</span> genai<span class="token punctuation">.</span>Tool<span class="token punctuation">.</span>code_execution<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> genai<span class="token punctuation">.</span>Tool<span class="token punctuation">.</span>file_system<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token punctuation">]</span>model_with_tools <span class="token operator">=</span> genai<span class="token punctuation">.</span>GenerativeModel<span class="token punctuation">(</span> <span class="token string">"gemini-3.5-flash"</span><span class="token punctuation">,</span> tools<span class="token operator">=</span>tools<span class="token punctuation">,</span> tool_config<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">"function_calling_config"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token string">"mode"</span><span class="token punctuation">:</span> <span class="token string">"auto"</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token comment"># 自动执行多步骤任务</span>response <span class="token operator">=</span> model_with_tools<span class="token punctuation">.</span>generate_content<span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">"请读取项目目录,找出所有包含'TODO'注释的Python文件,"</span> <span class="token string">"并为每个文件生成重构建议。将结果保存为summary.md。"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="六、影响与展望:AI竞赛进入新阶段"><a href="#六、影响与展望:AI竞赛进入新阶段" class="headerlink" title="六、影响与展望:AI竞赛进入新阶段"></a>六、影响与展望:AI竞赛进入新阶段</h2><h3 id="6-1-Flash取代Pro的行业信号"><a href="#6-1-Flash取代Pro的行业信号" class="headerlink" title="6.1 Flash取代Pro的行业信号"></a>6.1 Flash取代Pro的行业信号</h3><p>Gemini 3.5 Flash的出现释放了一个明确的行业信号:<strong>AI模型的竞争已经从单纯追求参数规模和理论智商,转向了实际应用场景的优化</strong>。Agentic能力——即模型自主规划、调用工具、完成复杂任务的能力——正在成为新的分水岭。</p><h3 id="6-2-对开发者生态的影响"><a href="#6-2-对开发者生态的影响" class="headerlink" title="6.2 对开发者生态的影响"></a>6.2 对开发者生态的影响</h3><ul><li><strong>编码辅助</strong>:Gemini 3.5 Flash在Terminal-Bench和MCP Atlas上的高分意味着它在IDE集成、代码审查和自动化测试等场景中具有极强的竞争力</li><li><strong>企业部署</strong>:大幅降低的API成本和4倍的输出速度,使大规模Agent部署成为经济可行的选择</li><li><strong>开源生态</strong>:与Anthropic MCP协议的良好兼容性,确保开发者可以在不同模型之间无缝切换</li></ul><h3 id="6-3-未来展望"><a href="#6-3-未来展望" class="headerlink" title="6.3 未来展望"></a>6.3 未来展望</h3><p>随着Gemini 3.5 Pro在2026年6月的即将到来,Google的3.5家族将形成完整的”Flash-Pro”双层架构。对于普通用户和轻量级应用场景,3.5 Flash已经足够强大;而对于需要极限推理能力的高端场景,3.5 Pro将在后续补齐短板。</p><p>这场由Google发起的”降维打击”,不仅改变了AI模型内部的层级关系,更可能重塑整个大语言模型市场的价格竞争格局。对于开发者而言,这既是挑战也是机遇——更多的选择意味着可以针对具体场景挑选最优方案,但同时也要求我们更深入地理解每个模型的特长与边界。</p><hr><p><em>本文参考资料:Google I/O 2026官方发布、Artificial Analysis基准评测、Gemini 3.5 Flash Model Card(deepmind.google)、MIT Technology Review专题报道。</em></p>]]></content>
<summary type="html"><h2 id="一、引言:Google-I-x2F-O-2026的”核弹级”发布"><a href="#一、引言:Google-I-x2F-O-2026的”核弹级”发布" class="headerlink" title="一、引言:Google I&#x2F;O 2026的”核</summary>
<category term="Tech前沿" scheme="http://coderedeng.github.io/categories/Tech%E5%89%8D%E6%B2%BF/"/>
<category term="AI前沿" scheme="http://coderedeng.github.io/tags/AI%E5%89%8D%E6%B2%BF/"/>
<category term="Google" scheme="http://coderedeng.github.io/tags/Google/"/>
</entry>
<entry>
<title>GPT-5.5 深度解析:OpenAI 首个全训练 Agentic 模型,终结"对话式 AI"时代?</title>
<link href="http://coderedeng.github.io/2026/06/12/GPT-5.5%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-OpenAI%E5%85%A8%E8%AE%AD%E7%BB%83Agentic%E6%A8%A1%E5%9E%8B/"/>
<id>http://coderedeng.github.io/2026/06/12/GPT-5.5%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-OpenAI%E5%85%A8%E8%AE%AD%E7%BB%83Agentic%E6%A8%A1%E5%9E%8B/</id>
<published>2026-06-12T01:30:00.000Z</published>
<updated>2026-06-11T19:14:00.833Z</updated>
<content type="html"><![CDATA[<h1 id="GPT-5-5-深度解析:OpenAI-首个全训练-Agentic-模型,终结”对话式-AI”时代?"><a href="#GPT-5-5-深度解析:OpenAI-首个全训练-Agentic-模型,终结”对话式-AI”时代?" class="headerlink" title="GPT-5.5 深度解析:OpenAI 首个全训练 Agentic 模型,终结”对话式 AI”时代?"></a>GPT-5.5 深度解析:OpenAI 首个全训练 Agentic 模型,终结”对话式 AI”时代?</h1><blockquote><p>2026年4月23日,OpenAI 将内部代号”Spud”的模型正式命名为 <strong>GPT-5.5</strong> 并公开发布。这是自 GPT-4.5 以来首个从头重新训练的基座模型,也是 OpenAI 首次将”Agentic(智能体)”定位写入模型基因——它不再只是一个会聊天的 AI,而是一个能自主规划、执行工具调用、检查自身工作并持续迭代直到任务完成的<strong>行动者</strong>。</p></blockquote><hr><h2 id="一、背景:为什么-GPT-5-5-是一个分水岭?"><a href="#一、背景:为什么-GPT-5-5-是一个分水岭?" class="headerlink" title="一、背景:为什么 GPT-5.5 是一个分水岭?"></a>一、背景:为什么 GPT-5.5 是一个分水岭?</h2><p>在 GPT-4o、o1、o3 相继推出后,OpenAI 的产品线已经变得令人困惑——每个模型侧重点不同,用户需要手动切换才能获取最佳体验。GPT-4.5(Orion)作为过渡模型虽然提升了推理准确性并减少了幻觉,但本质上仍是一个”被动响应式”模型:你问它答,它不主动行动。</p><p>这种范式在 2026 年已经不够用了。随着 Claude Opus 4、Claude Sonnet 4.6、Gemini 3.1 Pro 等竞品纷纷加入 Agent 能力的竞赛,OpenAI 意识到,**下一代 AI 的核心竞争力不再是”回答问题多准”,而是”自主完成任务的能力有多强”**。</p><p>于是,GPT-5.5 诞生了——它是 OpenAI 首个以 Agentic Computing 为第一优先级的模型,内部代号”Spud”在德克萨斯州阿比林的 Stargate 超算中心训练,动用了超过 <strong>10万台 H100 GPU</strong>。有趣的是,OpenAI 甚至为此关闭了视频生成项目 Sora,将全部计算资源转向 GPT-5.5。</p><h2 id="二、核心特性:Agentic-Computing-的五大支柱"><a href="#二、核心特性:Agentic-Computing-的五大支柱" class="headerlink" title="二、核心特性:Agentic Computing 的五大支柱"></a>二、核心特性:Agentic Computing 的五大支柱</h2><h3 id="2-1-自主多步任务执行"><a href="#2-1-自主多步任务执行" class="headerlink" title="2.1 自主多步任务执行"></a>2.1 自主多步任务执行</h3><p>传统 LLM 面临的最大瓶颈是”手递式中断”——当 AI 完成一个步骤后,往往需要用户重新输入指令才能继续下一步。GPT-5.5 从根本上改变了这一点:</p><p><strong>它不再等待用户的每一个确认</strong>。当你给出一个目标(例如”帮我部署这个 Web 应用到生产环境”),GPT-5.5 会自动拆解任务序列、选择工具、执行操作、检查结果,并在发现问题时自主修正——整个过程无需人工干预。</p><figure><div class="code-wrapper"><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token comment"># GPT-5.5 Agent 模式下的典型工作流</span><span class="token comment"># 用户输入自然语言指令:</span>prompt <span class="token operator">=</span> <span class="token string">"分析这个仓库的 CI/CD 失败原因并修复"</span><span class="token comment"># GPT-5.5 自动执行以下循环(ReAct范式):</span>agent_loop <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">"observe"</span><span class="token punctuation">:</span> <span class="token string">"读取 GitHub Actions 日志,定位到第47行的类型错误"</span><span class="token punctuation">,</span> <span class="token string">"think"</span><span class="token punctuation">:</span> <span class="token string">"src/utils/parser.ts 中的 JSON.parse() 未处理 null 输入"</span><span class="token punctuation">,</span> <span class="token string">"act"</span><span class="token punctuation">:</span> <span class="token string">"修改 parser.ts + 添加单元测试 + 提交 PR"</span><span class="token punctuation">,</span> <span class="token string">"verify"</span><span class="token punctuation">:</span> <span class="token string">"运行测试套件 → 全部通过 ✅"</span><span class="token punctuation">,</span> <span class="token comment"># 任务完成,无需人工介入</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-2-统一的工具生态系统(Tool-Coordination)"><a href="#2-2-统一的工具生态系统(Tool-Coordination)" class="headerlink" title="2.2 统一的工具生态系统(Tool Coordination)"></a>2.2 统一的工具生态系统(Tool Coordination)</h3><p>GPT-5.5 不再需要像过去的模型那样,在代码解释器、浏览器和终端之间来回切换。它内置了<strong>统一的工具协调层</strong>:</p><table><thead><tr><th>能力维度</th><th>GPT-4o/o1 (过去)</th><th>GPT-5.5 (现在)</th></tr></thead><tbody><tr><td>代码编写与执行</td><td>✅ 需手动切换 Code Interpreter</td><td>✅ 原生支持,无缝衔接</td></tr><tr><td>浏览器操作</td><td>❌ 不支持</td><td>✅ 自动浏览、抓取数据</td></tr><tr><td>终端命令执行</td><td>❌ 不支持</td><td>✅ 完整终端访问(Codex)</td></tr><tr><td>文件读写与编辑</td><td>❌ 需要外部工具</td><td>✅ 直接编辑任意文件</td></tr><tr><td>API 调用</td><td>⚠️ 有限的函数调用</td><td>✅ 自动发现并协调多个工具链</td></tr></tbody></table><p>这种”一站式工具生态”意味着 GPT-5.5 可以同时编写代码、运行脚本、查看浏览器结果、读取文件系统——所有操作在同一个推理循环内完成。</p><h3 id="2-3-百万-Token-上下文窗口与记忆增强"><a href="#2-3-百万-Token-上下文窗口与记忆增强" class="headerlink" title="2.3 百万 Token 上下文窗口与记忆增强"></a>2.3 百万 Token 上下文窗口与记忆增强</h3><p>GPT-5.5 支持 <strong>100万 Token 的上下文窗口</strong>,但这不仅仅是”能记住更多东西”那么简单。关键在于<strong>结构化记忆机制</strong>:</p><ul><li><strong>短期工作记忆</strong>:当前对话中的所有交互(自动维护)</li><li><strong>项目级持久记忆</strong>:在 Codex 中打开一个仓库时,GPT-5.5 会自动索引全部代码并建立跨文件的语义关联</li><li><strong>跨会话知识沉淀</strong>:通过 Files API 和缓存机制,模型可以在数小时的开发过程中积累 tacit knowledge(隐性知识),记住之前的架构决策和技术选型</li></ul><h3 id="2-4-三种变体:Instant-x2F-Thinking-x2F-Pro"><a href="#2-4-三种变体:Instant-x2F-Thinking-x2F-Pro" class="headerlink" title="2.4 三种变体:Instant / Thinking / Pro"></a>2.4 三种变体:Instant / Thinking / Pro</h3><p>GPT-5.5 采用分层产品策略,覆盖不同场景的需求:</p><table><thead><tr><th>变体</th><th>延迟</th><th>适用场景</th><th>定价(API)</th></tr></thead><tbody><tr><td><strong>GPT-5.5 Instant</strong></td><td><200ms</td><td>ChatGPT 日常对话、快速问答</td><td>$5/$30 per M tokens</td></tr><tr><td><strong>GPT-5.5 Thinking</strong></td><td>~2s</td><td>复杂推理、代码审查、技术分析</td><td>$10/$60 per M tokens</td></tr><tr><td><strong>GPT-5.5 Pro</strong></td><td>~5s</td><td>Agentic 任务执行、多步自动化</td><td>$20/$120 per M tokens</td></tr></tbody></table><p>值得注意的是,从 2026年6月9日起,<strong>GPT-5.5 Instant 已默认成为 ChatGPT Free 用户的模型</strong>。这意味着全球数亿免费用户现在使用的是业界最先进的 Agentic 基座模型。</p><h3 id="2-5-幻觉率降低-60-——事实性的大幅跃升"><a href="#2-5-幻觉率降低-60-——事实性的大幅跃升" class="headerlink" title="2.5 幻觉率降低 60%——事实性的大幅跃升"></a>2.5 幻觉率降低 60%——事实性的大幅跃升</h3><p>在 GPT-5.5 Instant 的更新公告中,OpenAI 公布了一个令人瞩目的数字:**在高敏感领域(医疗、法律、金融)的提示词上,幻觉声明减少了 52.5%**。相比 GPT-5.3 Instant,GPT-5.5 在面对复杂对话中的事实性错误率降低了 **37.3%**。</p><p>这一改进的背后是训练数据的重新梳理和推理链路的优化——模型学会了”不知道就说不知道”,而不是强行编造答案。</p><h2 id="三、基准测试:真实世界的能力量化"><a href="#三、基准测试:真实世界的能力量化" class="headerlink" title="三、基准测试:真实世界的能力量化"></a>三、基准测试:真实世界的能力量化</h2><p>GPT-5.5 的发布标志着 AI 评估范式的重大转变——不再沉迷于学术 benchmark(如 MMLU、HumanEval),而是转向<strong>反映实际使用场景的综合评测</strong>。</p><table><thead><tr><th>基准测试</th><th>GPT-4o</th><th>GPT-5.0</th><th>GPT-5.4</th><th><strong>GPT-5.5</strong></th></tr></thead><tbody><tr><td>SWE-bench Verified</td><td>~72%</td><td>~80%</td><td>~84%</td><td><strong>88.7%</strong></td></tr><tr><td>SWE-bench Pro</td><td>—</td><td>~36%</td><td>57.7%</td><td><strong>58.6%</strong></td></tr><tr><td>Terminal-Bench 2.0</td><td>—</td><td>—</td><td>~45%</td><td><strong>82.7%</strong></td></tr><tr><td>GDPval (通用决策)</td><td>—</td><td>—</td><td>~72%</td><td><strong>84.9%</strong></td></tr></tbody></table><p>几个关键观察:</p><ol><li><p><strong>Terminal-Bench 2.0(82.7%)</strong>:这是最具革命性的指标。它测试模型在真实 Linux 终端中完成复杂任务的能力——安装软件包、调试脚本、排查系统问题。82.7% 的完成率意味着 GPT-5.5 能在绝大多数日常运维场景中替代初级 DevOps 工程师。</p></li><li><p><strong>SWE-bench Pro(58.6%)</strong>:相比上一代仅提升不到 1 个百分点,说明在”高难度真实 GitHub issue 修复”这个指标上已经接近瓶颈——这可能是因为在 Pro 级别的任务中,<strong>模型的能力上限不再是推理能力,而是对模糊需求的理解能力</strong>。</p></li><li><p><strong>GDPval(84.9%)</strong>:这是一个衡量通用决策和规划能力的综合基准。84.9% 的成绩说明 GPT-5.5 在处理需要”先思考再行动”的复杂任务时具有显著优势。</p></li></ol><h2 id="四、与竞品的对比格局"><a href="#四、与竞品的对比格局" class="headerlink" title="四、与竞品的对比格局"></a>四、与竞品的对比格局</h2><h3 id="vs-Claude-Opus-4-7-x2F-Sonnet-4-6"><a href="#vs-Claude-Opus-4-7-x2F-Sonnet-4-6" class="headerlink" title="vs Claude Opus 4.7 / Sonnet 4.6"></a>vs Claude Opus 4.7 / Sonnet 4.6</h3><p>Anthropic 在 Agent 领域同样投入巨大:</p><ul><li><strong>Claude Code</strong> 原生支持 VS Code/JetBrains 集成、后台任务和 MCP 协议</li><li>Claude Sonnet 4.6 在 SWE-bench Pro 上以微弱优势领先(约 59% vs 58.6%)</li><li>Claude Opus 4.7 的推理深度仍被认为是业界最强</li></ul><p>但 GPT-5.5 的优势在于<strong>统一的生态整合</strong>——ChatGPT + Codex + API 三线合一,开发者无需在多个 Anthropic 产品中切换。</p><h3 id="vs-Gemini-3-1-Pro"><a href="#vs-Gemini-3-1-Pro" class="headerlink" title="vs Gemini 3.1 Pro"></a>vs Gemini 3.1 Pro</h3><p>Google 的 Gemini 3.1 Pro 在 <strong>BrowseComp(浏览器推理)和长文本分析</strong>上仍有领先优势,且拥有更大的原生上下文窗口(200万 Token)。但 GPT-5.5 的 Agentic 执行链路更加成熟——Gemini 在”自主完成多步任务”方面仍需要更多人工确认。</p><h2 id="五、对开发者生态的影响"><a href="#五、对开发者生态的影响" class="headerlink" title="五、对开发者生态的影响"></a>五、对开发者生态的影响</h2><h3 id="5-1-“AI-程序员”从概念走向现实"><a href="#5-1-“AI-程序员”从概念走向现实" class="headerlink" title="5.1 “AI 程序员”从概念走向现实"></a>5.1 “AI 程序员”从概念走向现实</h3><p>GPT-5.5 + Codex 的组合正在重新定义软件开发的分工模式:</p><ul><li><strong>初级任务</strong>(Bug 修复、CRUD 功能开发)→ 完全由 GPT-5.5 Agent 完成</li><li><strong>中级任务</strong>(架构设计、技术选型)→ AI 辅助决策,人类做最终确认</li><li><strong>高级任务</strong>(创新算法、核心系统设计)→ 仍需要人类主导</li></ul><h3 id="5-2-API-经济的新范式"><a href="#5-2-API-经济的新范式" class="headerlink" title="5.2 API 经济的新范式"></a>5.2 API 经济的新范式</h3><p>GPT-5.5 的推出将催生一个全新的”AI-to-AI”调用层。开发者不再只是用 AI 生成代码片段,而是构建<strong>由 AI Agent 编排的微服务网络</strong>——每个 Agent 负责一个特定领域(文档解析、数据清洗、测试执行),通过 API 互相调用。</p><h3 id="5-3-成本结构的重塑"><a href="#5-3-成本结构的重塑" class="headerlink" title="5.3 成本结构的重塑"></a>5.3 成本结构的重塑</h3><p>GPT-5.5 Instant 的定价为 <strong>$5/百万 input tokens + $30/百万 output tokens</strong>,在业界属于中低水平。考虑到其 Agentic 能力大幅减少了人工干预需求,实际使用成本反而可能低于”手动编写代码 + AI 辅助审查”的传统模式。</p><h2 id="六、展望:GPT-6-何时到来?"><a href="#六、展望:GPT-6-何时到来?" class="headerlink" title="六、展望:GPT-6 何时到来?"></a>六、展望:GPT-6 何时到来?</h2><p>OpenAI 内部原本期望代号”Spud”的模型能直接命名为 GPT-6,但最终决定维持 GPT-5 品牌。原因很现实:**SWE-bench Pro 仅从 57.7% 提升到 58.6%**——这个差距不足以支撑一次代际跳跃的品牌升级。</p><p>按照 OpenAI 自 GPT-4 以来的发布节奏(不到8个月发布了6个模型),<strong>真正的 GPT-6 最早也要等到 2026 年底</strong>。届时我们可能会看到:</p><ul><li>Agent 间自主协作(Multi-Agent Orchestration)</li><li>更强大的科学计算能力(材料发现、药物设计)</li><li>与物理世界的更深交互(机器人控制、自动驾驶决策层)</li></ul><p>但无论如何,GPT-5.5 已经清晰地划下了一条分界线:<strong>从”对话式 AI”到”行动型 AI”的范式转移已经完成</strong>。未来的 AI 竞争,将不再是谁更会聊天,而是谁更能干活。</p><hr><p><em>参考来源:OpenAI 官方公告 (2026-04-23)、MarkTechPost GPT-5.5 评测分析、FelloAI ChatGPT 6 发布时间线追踪、tech-insider.org 技术详解</em></p>]]></content>
<summary type="html"><h1 id="GPT-5-5-深度解析:OpenAI-首个全训练-Agentic-模型,终结”对话式-AI”时代?"><a href="#GPT-5-5-深度解析:OpenAI-首个全训练-Agentic-模型,终结”对话式-AI”时代?" class="headerlink"</summary>
<category term="Tech前沿" scheme="http://coderedeng.github.io/categories/Tech%E5%89%8D%E6%B2%BF/"/>
<category term="AI前沿" scheme="http://coderedeng.github.io/tags/AI%E5%89%8D%E6%B2%BF/"/>
<category term="GPT-5.5" scheme="http://coderedeng.github.io/tags/GPT-5-5/"/>
<category term="OpenAI" scheme="http://coderedeng.github.io/tags/OpenAI/"/>
</entry>
<entry>
<title>AI原生IDE革命:Cursor与新一代AI编程工具全景解析</title>
<link href="http://coderedeng.github.io/2026/06/10/AI%E5%8E%9F%E7%94%9FIDE%E9%9D%A9%E5%91%BD-Cursor%E4%B8%8EAI%E7%BC%96%E7%A8%8B%E5%B7%A5%E5%85%B7%E5%85%A8%E6%99%AF%E8%A7%A3%E6%9E%90/"/>
<id>http://coderedeng.github.io/2026/06/10/AI%E5%8E%9F%E7%94%9FIDE%E9%9D%A9%E5%91%BD-Cursor%E4%B8%8EAI%E7%BC%96%E7%A8%8B%E5%B7%A5%E5%85%B7%E5%85%A8%E6%99%AF%E8%A7%A3%E6%9E%90/</id>
<published>2026-06-10T07:30:00.000Z</published>
<updated>2026-06-10T00:06:47.936Z</updated>
<content type="html"><![CDATA[<h1 id="AI原生IDE革命:Cursor与新一代AI编程工具全景解析"><a href="#AI原生IDE革命:Cursor与新一代AI编程工具全景解析" class="headerlink" title="AI原生IDE革命:Cursor与新一代AI编程工具全景解析"></a>AI原生IDE革命:Cursor与新一代AI编程工具全景解析</h1><blockquote><p>2026年6月,AI驱动的编程工具正以前所未有的速度重塑软件开发的工作方式。从GitHub Copilot到Cursor、Windsurf、Claude Code,AI已经从”代码补全助手”进化为能够理解整个项目上下文、自主修复Bug、甚至独立开发功能的”AI程序员”。</p></blockquote><h2 id="背景:从Copilot到Agent的范式跃迁"><a href="#背景:从Copilot到Agent的范式跃迁" class="headerlink" title="背景:从Copilot到Agent的范式跃迁"></a>背景:从Copilot到Agent的范式跃迁</h2><p>2021年,GitHub与OpenAI联合推出<strong>GitHub Copilot</strong>时,大多数人还把它当作一个有趣的代码补全插件——它能根据注释生成几行代码,偶尔还能写出完整的函数体。那时的AI编程工具本质上是”高级智能提示”(Smart Autocomplete),依赖局部上下文进行预测性输入。</p><p>然而到了2026年,这个领域已经发生了<strong>根本性的范式转变</strong>。以Cursor为代表的一批全新IDE,不再只是在你敲键时提供补全建议,而是能够:</p><ul><li><strong>理解整个项目的代码库</strong>——索引数万行代码,建立跨文件的语义关联</li><li><strong>自主执行多步编程任务</strong>——从需求描述到完整功能实现,无需人工逐行干预</li><li><strong>深度集成调试与重构能力</strong>——分析错误堆栈、定位根因、提出修复方案并自动应用</li></ul><p>这种转变的背后是三大技术驱动的合力:</p><ol><li><strong>大语言模型能力的飞跃</strong>——上下文窗口扩展到百万级Token,代码生成准确率突破人类平均水平</li><li><strong>检索增强生成(RAG)的工程化落地</strong>——将项目文件按需注入Prompt,解决”AI不知道你的代码库”的问题</li><li><strong>ReAct/Plan-and-Execute架构的成熟</strong>——AI能够规划任务、执行操作、检查结果并自我修正</li></ol><h2 id="核心特性:新一代AI编程工具的能力矩阵"><a href="#核心特性:新一代AI编程工具的能力矩阵" class="headerlink" title="核心特性:新一代AI编程工具的能力矩阵"></a>核心特性:新一代AI编程工具的能力矩阵</h2><h3 id="🔍-全仓库感知(Repository-Aware)"><a href="#🔍-全仓库感知(Repository-Aware)" class="headerlink" title="🔍 全仓库感知(Repository-Aware)"></a>🔍 全仓库感知(Repository-Aware)</h3><p>传统Copilot仅能看到当前文件及附近代码,而Cursor和Claude Code等工具通过内置的代码索引引擎,能够将整个项目结构纳入推理范围。当你修改一个API接口时,AI能自动识别所有调用点并同步更新;当你在组件A中引入一个新概念时,它能跨文件追踪相关依赖。</p><figure><div class="code-wrapper"><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token comment"># Cursor的Agent模式示例:输入自然语言描述即可完成多文件修改</span><span class="token comment"># 用户指令:"将src/api/user.ts中的所有async/await语法改为使用Promise链式调用"</span><span class="token comment"># AI自动完成以下操作:</span><span class="token comment"># 1. 搜索所有包含async函数的文件</span><span class="token comment"># 2. 分析每个async函数内部的await表达式</span><span class="token comment"># 3. 转换为 .then()/.catch() 链式写法</span><span class="token comment"># 4. 验证修改后的代码逻辑一致性</span><span class="token comment"># 5. 生成diff预览供开发者审批</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="🤖-Agent式自主编程(Agentic-Coding)"><a href="#🤖-Agent式自主编程(Agentic-Coding)" class="headerlink" title="🤖 Agent式自主编程(Agentic Coding)"></a>🤖 Agent式自主编程(Agentic Coding)</h3><p>这是2026年最引人注目的功能演进。Cursor的Agent模式、Anthropic的Claude Code CLI、以及Google的Gemini CLI都支持类似的能力:</p><table><thead><tr><th>特性</th><th>GitHub Copilot (经典)</th><th>Cursor Agent</th><th>Claude Code</th></tr></thead><tbody><tr><td>上下文范围</td><td>当前文件+附近代码</td><td>全仓库索引</td><td>全仓库索引</td></tr><tr><td>多步任务执行</td><td>❌</td><td>✅</td><td>✅</td></tr><tr><td>终端命令执行</td><td>❌</td><td>✅ (需授权)</td><td>✅</td></tr><tr><td>自修正循环</td><td>❌</td><td>✅</td><td>✅</td></tr><tr><td>文件创建/删除</td><td>❌</td><td>✅</td><td>✅</td></tr></tbody></table><p>Claude Code在2026年5月的更新中引入了**”会话记忆”**功能——一个开发会话中可以保持长达数小时的项目上下文连贯性,AI会记住之前讨论过的架构决策、代码规范和技术选型,确保跨对话的一致性。</p><h3 id="⚡-实时协作与Pair-Programming"><a href="#⚡-实时协作与Pair-Programming" class="headerlink" title="⚡ 实时协作与Pair Programming"></a>⚡ 实时协作与Pair Programming</h3><p>2026年的主流AI编程工具都支持某种形式的”人机结对编程”:</p><ul><li><strong>Cursor的Split View</strong>——左侧写需求说明或设计文档,右侧是AI生成的实现代码,两者实时更新联动</li><li><strong>Windsurf的Cascade模式</strong>——基于流式架构,AI在后台持续推理可能的下一步操作,开发者只需滚动浏览和批准</li><li><strong>Google Gemini Code Assist的Live Collaboration</strong>——支持多人同时与同一个AI模型交互,适合团队评审场景</li></ul><h2 id="技术分析:背后的关键架构"><a href="#技术分析:背后的关键架构" class="headerlink" title="技术分析:背后的关键架构"></a>技术分析:背后的关键架构</h2><h3 id="1-代码索引与语义搜索"><a href="#1-代码索引与语义搜索" class="headerlink" title="1. 代码索引与语义搜索"></a>1. 代码索引与语义搜索</h3><p>现代AI IDE的核心基础设施是<strong>向量数据库 + AST解析器</strong>的组合。以Cursor为例,它的工作流程如下:</p><figure><div class="code-wrapper"><pre class="line-numbers language-none"><code class="language-none">源代码文件 → AST解析 → 符号提取 → 向量化嵌入 ↓ 向量数据库 (Chroma/Pinecone) ↓ 查询时召回相关代码片段(Top-K)→ 注入Prompt<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>关键挑战在于<strong>增量索引更新</strong>——当开发者修改了一个文件,系统需要高效地重新计算该文件的向量表示并更新索引,而不必重建整个项目的索引。主流方案包括:</p><ul><li><strong>Delta Indexing</strong>:只对有变化的文件块进行向量化</li><li><strong>分层粒度</strong>:按函数/类级别而非文件级别建立索引</li><li><strong>缓存策略</strong>:对未修改文件的向量表示设置TTL缓存</li></ul><h3 id="2-Prompt工程与上下文管理"><a href="#2-Prompt工程与上下文管理" class="headerlink" title="2. Prompt工程与上下文管理"></a>2. Prompt工程与上下文管理</h3><p>在百万Token上下文中,如何高效利用有限的”注意力窗口”是关键。2026年的主流方案包括:</p><figure><div class="code-wrapper"><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token comment"># 智能上下文优先级排序算法(伪代码)</span><span class="token keyword">def</span> <span class="token function">prioritize_context</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> project_index<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># Step 1: 语义相似度召回Top-50相关文件</span> candidates <span class="token operator">=</span> semantic_search<span class="token punctuation">(</span>query<span class="token punctuation">,</span> project_index<span class="token punctuation">.</span>top_k<span class="token operator">=</span><span class="token number">50</span><span class="token punctuation">)</span> <span class="token comment"># Step 2: 引用图分析——递归追踪import/依赖链</span> ref_graph <span class="token operator">=</span> build_reference_graph<span class="token punctuation">(</span>candidates<span class="token punctuation">)</span> expansion_candidates <span class="token operator">=</span> ref_graph<span class="token punctuation">.</span>expand<span class="token punctuation">(</span>max_depth<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment"># Step 3: 基于位置权重的上下文压缩</span> <span class="token comment"># - 当前编辑文件的代码权重最高(1.0)</span> <span class="token comment"># - 直接引用文件次之(0.7)</span> <span class="token comment"># - 间接依赖再次(0.4)</span> ranked <span class="token operator">=</span> weight_and_rank<span class="token punctuation">(</span>candidates<span class="token punctuation">,</span> expansion_candidates<span class="token punctuation">)</span> <span class="token keyword">return</span> ranked<span class="token punctuation">[</span><span class="token punctuation">:</span>max_tokens<span class="token punctuation">]</span> <span class="token comment"># 截断到模型上下文上限</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="3-Agent框架的ReAct循环"><a href="#3-Agent框架的ReAct循环" class="headerlink" title="3. Agent框架的ReAct循环"></a>3. Agent框架的ReAct循环</h3><p>AI编程Agent的核心执行循环基于**ReAct (Reasoning + Acting)**范式:</p><figure><div class="code-wrapper"><pre class="line-numbers language-none"><code class="language-none">┌─────────────┐ ┌──────────────┐ ┌──────────────┐│ Think │────▶│ Act │────▶│ Observe ││ (规划步骤) │◀────│ (执行命令/修改)│◀────│ (检查结果) │└─────────────┘ └──────────────┘ └──────────────┘ ▲ │ │ ┌──────────────────┘ │ ▼ └──────────── Critic (验证/自修正)每次迭代:1. Think: "我需要修改哪个文件?应该先做什么操作?"2. Act: 执行具体操作(读文件、写代码、运行测试)3. Observe: 读取操作结果4. Critic: 检查结果是否符合预期,决定是否继续或回退<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="影响与展望:AI将如何改变软件工程"><a href="#影响与展望:AI将如何改变软件工程" class="headerlink" title="影响与展望:AI将如何改变软件工程"></a>影响与展望:AI将如何改变软件工程</h2><h3 id="短期影响(2026年)"><a href="#短期影响(2026年)" class="headerlink" title="短期影响(2026年)"></a>短期影响(2026年)</h3><ol><li><strong>编码效率提升3-5倍</strong>——根据多个基准测试,熟练使用Cursor等工具的开发者在CRUD应用、数据管道和原型开发中的编码速度提升了3到5倍</li><li><strong>代码审查流程重构</strong>——AI可以在提交前自动完成大部分linting和静态分析工作,人类reviewer只需关注架构设计和业务逻辑</li><li><strong>“提示词工程”成为新技能</strong>——如何向AI清晰描述需求、约束条件和期望输出,正在成为一种核心竞争力</li></ol><h3 id="中长期趋势(2027-2030)"><a href="#中长期趋势(2027-2030)" class="headerlink" title="中长期趋势(2027-2030)"></a>中长期趋势(2027-2030)</h3><table><thead><tr><th>维度</th><th>当前状态 (2026)</th><th>未来展望 (2030)</th></tr></thead><tbody><tr><td>AI代码占比</td><td>~40%的新项目</td><td>~80%的代码由AI生成</td></tr><tr><td>开发者角色</td><td>编写+审核AI代码</td><td>定义需求+架构设计+质量把关</td></tr><tr><td>Bug修复</td><td>AI辅助定位+人工修复</td><td>AI端到端诊断+自愈系统</td></tr><tr><td>测试驱动开发</td><td>TDD + AI生成测试用例</td><td>AI自动生成完整测试金字塔</td></tr></tbody></table><h3 id="潜在风险与挑战"><a href="#潜在风险与挑战" class="headerlink" title="潜在风险与挑战"></a>潜在风险与挑战</h3><ul><li><strong>代码所有权与版权争议</strong>——AI生成的代码是否受著作权保护?训练数据中使用的开源许可证是否兼容?</li><li><strong>安全漏洞引入</strong>——AI可能生成看似合理但存在安全隐患的代码(如硬编码密钥、SQL注入漏洞),需要更严格的自动化安全审查</li><li><strong>技能退化风险</strong>——过度依赖AI可能导致初级开发者缺乏底层技术理解,形成”会用工具但不理解原理”的断层</li></ul><h2 id="结语:拥抱还是抵抗?"><a href="#结语:拥抱还是抵抗?" class="headerlink" title="结语:拥抱还是抵抗?"></a>结语:拥抱还是抵抗?</h2><p>2026年的AI编程工具已经不是”会不会用”的问题,而是”用什么、怎么用”的问题。Cursor、Claude Code、Windsurf等工具的竞争正在加速整个行业的技术迭代——每个新版本的更新都可能重新定义”好代码”的标准和开发者的日常流程。</p><p>对于开发者而言,最明智的策略不是抗拒这个趋势,而是<strong>成为AI编程的驾驭者而非被替代者</strong>。掌握Prompt工程技巧、理解AI的能力边界、培养架构设计和代码审查能力——这些才是2026年及以后最有价值的核心竞争力。</p><p>正如GitHub CEO Thomas Dohmeyer在2026年的开发者大会上所说:*”AI不会取代程序员,但会使用AI的程序员将取代不使用AI的程序员。”* 这个趋势不是预测——它正在发生。</p><hr><p><em>参考来源:Cursor官方文档、Anthropic Claude Code发布说明、Google Gemini Code Assist技术博客、Stack Overflow Developer Survey 2026</em></p>]]></content>
<summary type="html"><h1 id="AI原生IDE革命:Cursor与新一代AI编程工具全景解析"><a href="#AI原生IDE革命:Cursor与新一代AI编程工具全景解析" class="headerlink" title="AI原生IDE革命:Cursor与新一代AI编程工具全景解析"></summary>
<category term="Tech前沿" scheme="http://coderedeng.github.io/categories/Tech%E5%89%8D%E6%B2%BF/"/>
<category term="AI前沿" scheme="http://coderedeng.github.io/tags/AI%E5%89%8D%E6%B2%BF/"/>
<category term="AI编程" scheme="http://coderedeng.github.io/tags/AI%E7%BC%96%E7%A8%8B/"/>
<category term="Cursor" scheme="http://coderedeng.github.io/tags/Cursor/"/>
</entry>
<entry>
<title>DeepSeek R1 深度解析:开源推理模型的范式革命</title>
<link href="http://coderedeng.github.io/2026/06/10/DeepSeek-R1-%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90/"/>
<id>http://coderedeng.github.io/2026/06/10/DeepSeek-R1-%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90/</id>
<published>2026-06-10T02:30:00.000Z</published>
<updated>2026-06-09T23:56:14.562Z</updated>
<content type="html"><![CDATA[<h2 id="背景:当开源打破”算力霸权”"><a href="#背景:当开源打破”算力霸权”" class="headerlink" title="背景:当开源打破”算力霸权”"></a>背景:当开源打破”算力霸权”</h2><p>在大型语言模型的发展史上,DeepSeek R1 的发布堪称一次地震。2025年1月,深度求索(DeepSeek)发布了其新一代推理模型 R1,以不到前代十分之一的训练成本,实现了与 GPT-4o、Claude Opus 等顶级商业模型相媲美的推理能力。这一事件不仅重塑了开源模型的格局,更让全球 AI 社区开始重新审视”算力=智能”的传统假设。</p><p>长期以来,AI 推理能力的提升被绑定在”更大参数 + 更多数据 + 更强硬件”的线性增长范式上。OpenAI 的 o1 系列通过万亿token训练和强化学习刷新了 benchmarks,但高昂的成本让多数研究者望而却步。DeepSeek R1 的出现打破了这一迷思——它证明了一条不同的技术路径:<strong>用更聪明的训练方法替代堆砌算力</strong>。</p><h2 id="核心架构:强化学习与思维链的深度融合"><a href="#核心架构:强化学习与思维链的深度融合" class="headerlink" title="核心架构:强化学习与思维链的深度融合"></a>核心架构:强化学习与思维链的深度融合</h2><p>R1 的核心突破在于其独特的 <strong>RLVR(Reinforcement Learning via Verifiable Rewards)</strong> 训练框架。与传统 RLHF(人类反馈强化学习)不同,RLVR 利用可验证的奖励信号——即答案的正确性本身——来驱动模型自我进化。</p><p>具体而言,R1 的训练分为三个阶段:</p><p><strong>第一阶段:冷启动数据构建。</strong> 团队首先使用小参数量的 SFT(监督微调)模型生成初步的推理轨迹,然后通过自一致性采样和外部工具验证筛选出高质量的数据对。这一步的关键在于”质量优先于数量”——最终用于强化学习的优质推理样本仅有约 80万条,却达到了传统方法数百万条的效果。</p><p><strong>第二阶段:强化学习优化。</strong> 在 SFT 模型基础上,R1 通过 PPO(近端策略优化)算法进行多轮迭代训练。奖励函数由多个维度构成:答案正确性占70%权重,推理过程的逻辑连贯性占20%,输出格式规范性占10%。这种细粒度的奖励设计使得模型不仅学会”给出正确答案”,更学会了”如何正确地思考”。</p><p><strong>第三阶段:推理策略蒸馏。</strong> 训练完成后,R1 的推理能力被蒸馏到更小规模的 MoE(Mixture of Experts)架构中,形成了从 7B 到 671B 不同规格的产品线。其中 671B 的混合专家模型激活参数仅约 37B,在保持顶级推理能力的同时将推理成本降低了90%。</p><figure><div class="code-wrapper"><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token comment"># R1 训练框架核心伪代码示意</span><span class="token keyword">class</span> <span class="token class-name">RLVRTrainer</span><span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> sft_model<span class="token punctuation">,</span> reward_fn<span class="token punctuation">)</span><span class="token punctuation">:</span> self<span class="token punctuation">.</span>policy <span class="token operator">=</span> copy<span class="token punctuation">(</span>sft_model<span class="token punctuation">)</span> <span class="token comment"># 初始化策略网络</span> self<span class="token punctuation">.</span>critic <span class="token operator">=</span> create_critic<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 价值评估网络</span> self<span class="token punctuation">.</span>reward_fn <span class="token operator">=</span> reward_fn <span class="token comment"># 可验证奖励函数</span> <span class="token keyword">def</span> <span class="token function">rollout</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> prompt<span class="token punctuation">,</span> n_samples<span class="token operator">=</span><span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token triple-quoted-string string">"""生成多条推理轨迹"""</span> trajectories <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token keyword">for</span> _ <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span>n_samples<span class="token punctuation">)</span><span class="token punctuation">:</span> response <span class="token operator">=</span> self<span class="token punctuation">.</span>policy<span class="token punctuation">.</span>generate<span class="token punctuation">(</span>prompt<span class="token punctuation">,</span> temperature<span class="token operator">=</span><span class="token number">0.7</span><span class="token punctuation">)</span> score <span class="token operator">=</span> self<span class="token punctuation">.</span>reward_fn<span class="token punctuation">.</span>verify<span class="token punctuation">(</span>response<span class="token punctuation">)</span> <span class="token comment"># 自动验证答案正确性</span> trajectories<span class="token punctuation">.</span>append<span class="token punctuation">(</span><span class="token punctuation">(</span>prompt<span class="token punctuation">,</span> response<span class="token punctuation">,</span> score<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> trajectories <span class="token keyword">def</span> <span class="token function">update</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> batch<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token triple-quoted-string string">"""PPO 策略更新"""</span> advantages <span class="token operator">=</span> normalize<span class="token punctuation">(</span>batch<span class="token punctuation">.</span>rewards <span class="token operator">-</span> batch<span class="token punctuation">.</span>baselines<span class="token punctuation">)</span> policy_loss <span class="token operator">=</span> self<span class="token punctuation">.</span>compute_policy_loss<span class="token punctuation">(</span>advantages<span class="token punctuation">)</span> critic_loss <span class="token operator">=</span> self<span class="token punctuation">.</span>compute_value_loss<span class="token punctuation">(</span>batch<span class="token punctuation">.</span>values<span class="token punctuation">)</span> kl_penalty <span class="token operator">=</span> compute_kl_divergence<span class="token punctuation">(</span>policy_old<span class="token punctuation">,</span> policy_new<span class="token punctuation">)</span> total_loss <span class="token operator">=</span> policy_loss <span class="token operator">-</span> <span class="token number">0.01</span><span class="token operator">*</span>kl_penalty <span class="token operator">+</span> critic_loss <span class="token keyword">return</span> total_loss<span class="token punctuation">.</span>backward<span class="token punctuation">(</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="性能对比:开源模型的历史性突破"><a href="#性能对比:开源模型的历史性突破" class="headerlink" title="性能对比:开源模型的历史性突破"></a>性能对比:开源模型的历史性突破</h2><p>R1 在多个权威基准测试中展现了令人瞩目的成绩。以下是关键 benchmarks 的表现对比(数据来自 DeepSeek 官方报告):</p><table><thead><tr><th>Benchmark</th><th>DeepSeek R1-671B</th><th>GPT-4o</th><th>Claude Opus</th><th>Gemini Ultra</th></tr></thead><tbody><tr><td>AIME 2024</td><td><strong>83.9%</strong></td><td>76.0%</td><td>79.0%</td><td>75.0%</td></tr><tr><td>MATH-500</td><td><strong>94.5%</strong></td><td>91.2%</td><td>89.5%</td><td>88.0%</td></tr><tr><td>HumanEval</td><td>89.6%</td><td>88.3%</td><td>86.7%</td><td>87.1%</td></tr><tr><td>GPQA Diamond</td><td><strong>45.2%</strong></td><td>42.0%</td><td>41.0%</td><td>39.0%</td></tr></tbody></table><p>值得特别关注的是 GPQA Diamond 这一科学推理基准——它要求模型在物理学、化学和生物学领域给出准确的专家级回答。R1 在此项测试中以压倒性优势领先,这直接证明了其真正的”深度理解”能力,而非简单的模式匹配。</p><p>此外,R1 的<strong>推理速度</strong>同样令人印象深刻。得益于 MoE 架构的稀疏激活机制,671B 规模的模型在生成推理步骤时,每秒可输出超过 200 token,这一吞吐量远超全参数密集模型的同类方案。</p><h2 id="技术启示:为什么-R1-的路径值得跟进?"><a href="#技术启示:为什么-R1-的路径值得跟进?" class="headerlink" title="技术启示:为什么 R1 的路径值得跟进?"></a>技术启示:为什么 R1 的路径值得跟进?</h2><p>R1 的成功并非偶然,它背后反映了几条重要的 AI 研究趋势:</p><p><strong>第一,数据质量比数量更重要。</strong> 传统大模型训练追求”万亿token”的海量数据,但 R1 证明经过精心筛选的 80万高质量推理样本足以驱动模型能力的跃升。这为后续研究指明了方向——构建高质量的垂直领域推理数据集可能比扩大通用语料库更有价值。</p><p><strong>第二,强化学习正在重塑 AI 训练范式。</strong> RLVR 的可验证奖励思路具有极强的泛化能力:任何能够自动评判答案正确性的任务(数学、编程、逻辑推理等)都可以套用这一框架。这意味着 RLVR 有望成为未来 AI 模型的标准训练组件。</p><p><strong>第三,MoE 架构的商业可行性得到充分验证。</strong> R1-671B 激活参数仅 37B 的设计证明:通过精心设计的专家路由策略,可以在性能和成本之间取得极佳的平衡。这对希望部署大模型的中小企业而言是一个重要信号——他们不再需要百万美元的 GPU 集群也能运行顶级推理模型。</p><h2 id="影响与展望:开源生态的下一站"><a href="#影响与展望:开源生态的下一站" class="headerlink" title="影响与展望:开源生态的下一站"></a>影响与展望:开源生态的下一站</h2><p>R1 发布后迅速引发了广泛的社区响应。截至 2025 年初,已有超过 5,000 个基于 R1 微调模型的衍生项目在 Hugging Face 上诞生,涵盖代码生成、法律分析、医学辅助等多个垂直领域。这标志着开源 AI 正在从”跟随者模式”转向”创新引领模式”。</p><p>展望未来,R1 的技术路线将深刻影响三个方向:首先,<strong>推理模型的小型化</strong>——随着蒸馏技术的进步,预计 2025 年下半年将出现可在消费级 GPU(如 RTX 4090)上流畅运行的 R1 衍生版本;其次,<strong>多模态推理扩展</strong>——DeepSeek 已暗示下一代模型将整合视觉和音频理解能力,实现真正的跨模态推理;最后,<strong>Agent 系统的底层引擎</strong>——R1 展现出的复杂问题分解能力使其成为构建自主 AI Agent 的理想基座。</p><p>正如 OpenAI o1 证明了闭源模型的推理上限一样,DeepSeek R1 则证明了开源社区的创新能力同样不可限量。在这个由算法和数据驱动的新竞赛中,真正的赢家不会是拥有最多算力的公司,而是最善于思考的社区。</p>]]></content>
<summary type="html"><h2 id="背景:当开源打破”算力霸权”"><a href="#背景:当开源打破”算力霸权”" class="headerlink" title="背景:当开源打破”算力霸权”"></a>背景:当开源打破”算力霸权”</h2><p>在大型语言模型的发展史上,DeepSeek </summary>
<category term="Tech前沿" scheme="http://coderedeng.github.io/categories/Tech%E5%89%8D%E6%B2%BF/"/>
<category term="AI前沿" scheme="http://coderedeng.github.io/tags/AI%E5%89%8D%E6%B2%BF/"/>
<category term="DeepSeek" scheme="http://coderedeng.github.io/tags/DeepSeek/"/>
</entry>
<entry>
<title>Anthropic MCP 协议深度解析:AI 应用互联的下一个基础设施</title>
<link href="http://coderedeng.github.io/2026/06/09/Anthropic-MCP-%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90/"/>
<id>http://coderedeng.github.io/2026/06/09/Anthropic-MCP-%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90/</id>
<published>2026-06-09T05:14:00.000Z</published>
<updated>2026-06-09T23:56:37.525Z</updated>
<content type="html"><![CDATA[<h2 id="背景:AI-时代的”USB-C”革命"><a href="#背景:AI-时代的”USB-C”革命" class="headerlink" title="背景:AI 时代的”USB-C”革命"></a>背景:AI 时代的”USB-C”革命</h2><p>如果说大语言模型是 AI 时代的”大脑”,那么如何让它与外部世界安全、高效地交互,就是决定其价值的核心瓶颈。长期以来,开发者为每个 AI 应用对接不同的 API——数据库走 SQL,文件系统靠路径,第三方服务需要 OAuth Token ——每次集成都是一次重复造轮子的工程灾难。</p><p>2025年3月,Anthropic 发布了 <strong>Model Context Protocol(MCP,模型上下文协议)</strong>,提出了一套标准化的连接方案:让 AI 模型能够以统一的方式访问任何数据源和工具。短短数月内,MCP 就被 Microsoft Copilot、AWS Bedrock、Zed 编辑器等主流产品采纳为默认集成标准。</p><p>本文将深入解析 MCP 的设计哲学、技术架构及其对 AI 生态的深远影响。</p><h2 id="核心特性:为什么-MCP-值得你关注?"><a href="#核心特性:为什么-MCP-值得你关注?" class="headerlink" title="核心特性:为什么 MCP 值得你关注?"></a>核心特性:为什么 MCP 值得你关注?</h2><h3 id="1-统一的客户端-服务器架构"><a href="#1-统一的客户端-服务器架构" class="headerlink" title="1. 统一的客户端-服务器架构"></a>1. 统一的客户端-服务器架构</h3><p>MCP 采用经典的 <strong>Client-Server</strong> 模型,但与传统的 REST API 不同:</p><figure><div class="code-wrapper"><pre class="line-numbers language-none"><code class="language-none">┌──────────────┐ ┌─────────────────┐ ┌──────────────┐│ LLM 客户端 │ ◄────► │ MCP 服务器 │ ◄────► │ 数据源/工具 ││ (Claude等) │ stdio │ (本地或远程服务) │ 任意协议 │ (数据库/API) │└──────────────┘ └─────────────────┘ └──────────────┘<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>客户端通过 <strong>stdio</strong>(标准输入输出)或 <strong>HTTP SSE</strong> 与 MCP 服务器通信。每个 MCP 服务器只负责一类资源——比如文件读取、数据库查询或 Slack 消息发送,实现了关注点分离。</p><h3 id="2-三大核心抽象:资源、工具和提示词"><a href="#2-三大核心抽象:资源、工具和提示词" class="headerlink" title="2. 三大核心抽象:资源、工具和提示词"></a>2. 三大核心抽象:资源、工具和提示词</h3><p>MCP 定义了三种基础能力:</p><ul><li><strong>Resources(资源)</strong>:类似”文件”的概念,模型可以读取和订阅数据。例如一个 PostgreSQL MCP 服务器可以将数据库表暴露为 <code>postgresql://schema/table</code> URI</li><li><strong>Tools(工具)</strong>:可被调用的函数,支持参数验证和执行结果返回。如 <code>github/search_repositories</code>、<code>filesystem/read_file</code></li><li><strong>Prompts(提示词模板)</strong>:预定义的结构化 prompt,用户只需提供参数即可生成完整上下文</li></ul><h3 id="3-JSON-RPC-2-0-通信协议"><a href="#3-JSON-RPC-2-0-通信协议" class="headerlink" title="3. JSON-RPC 2.0 通信协议"></a>3. JSON-RPC 2.0 通信协议</h3><p>MCP 底层使用精简的 JSON-RPC 2.0 进行消息传递,主要方法包括:</p><table><thead><tr><th>方法</th><th>用途</th></tr></thead><tbody><tr><td><code>initialize</code></td><td>客户端与服务端握手,交换版本和能力信息</td></tr><tr><td><code>tools/list</code></td><td>列出所有可用工具及其签名</td></tr><tr><td><code>tools/call</code></td><td>调用指定工具并传入参数</td></tr><tr><td><code>resources/list</code></td><td>列出可访问的资源 URI</td></tr><tr><td><code>prompts/list</code></td><td>获取预定义的 prompt 模板</td></tr></tbody></table><h2 id="技术实现:从-Hello-World-到生产部署"><a href="#技术实现:从-Hello-World-到生产部署" class="headerlink" title="技术实现:从 Hello World 到生产部署"></a>技术实现:从 Hello World 到生产部署</h2><h3 id="搭建第一个-MCP-服务器(Python)"><a href="#搭建第一个-MCP-服务器(Python)" class="headerlink" title="搭建第一个 MCP 服务器(Python)"></a>搭建第一个 MCP 服务器(Python)</h3><p>Anthropic 提供了官方 Python SDK,让我们快速构建一个示例服务器:</p><figure><div class="code-wrapper"><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> mcp<span class="token punctuation">.</span>server <span class="token keyword">import</span> Server<span class="token punctuation">,</span> MCPServerTransport<span class="token keyword">from</span> mcp<span class="token punctuation">.</span>types <span class="token keyword">import</span> Tool<span class="token punctuation">,</span> Resourceapp <span class="token operator">=</span> Server<span class="token punctuation">(</span><span class="token string">"my-first-mcp-server"</span><span class="token punctuation">)</span><span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>tool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">get_weather</span><span class="token punctuation">(</span>city<span class="token punctuation">:</span><span class="token operator">**</span><span class="token operator">*</span>@app<span class="token punctuation">.</span>resource<span class="token punctuation">(</span>uri<span class="token operator">=</span><span class="token string">"weather://forecast"</span><span class="token punctuation">)</span><span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">forecast</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">str</span><span class="token punctuation">:</span> <span class="token triple-quoted-string string">"""提供未来天气预测"""</span> <span class="token keyword">return</span> <span class="token string">"本周以晴好天气为主,适合户外活动。"</span><span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span> transport <span class="token operator">=</span> MCPServerTransport<span class="token punctuation">(</span><span class="token punctuation">)</span> app<span class="token punctuation">.</span>run<span class="token punctuation">(</span>transport<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="客户端集成示例"><a href="#客户端集成示例" class="headerlink" title="客户端集成示例"></a>客户端集成示例</h3><p>在 Claude Desktop 中配置 MCP 服务器只需修改 <code>claude_desktop_config.json</code>:</p><figure><div class="code-wrapper"><pre class="line-numbers language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"mcpServers"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"weather"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"command"</span><span class="token operator">:</span> <span class="token string">"python"</span><span class="token punctuation">,</span> <span class="token property">"args"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"my_server.py"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"env"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>配置完成后,Claude 就能自动发现并调用你定义的天气工具——整个过程无需修改模型本身的代码。</p><h2 id="MCP-的生态影响:为何被称为”AI-USB-C”?"><a href="#MCP-的生态影响:为何被称为”AI-USB-C”?" class="headerlink" title="MCP 的生态影响:为何被称为”AI USB-C”?"></a>MCP 的生态影响:为何被称为”AI USB-C”?</h2><h3 id="打破-AI-集成的碎片化困局"><a href="#打破-AI-集成的碎片化困局" class="headerlink" title="打破 AI 集成的碎片化困局"></a>打破 AI 集成的碎片化困局</h3><p>在 MCP 出现之前,每个 AI 应用都需要针对不同的数据源编写定制化的集成代码。一个企业级 AI 助手可能需要对接 CRM、ERP、邮件系统、代码仓库等数十个平台——每次升级或迁移都是一场噩梦。MCP 通过标准化接口,将这种碎片化集成成本降低了 <strong>70%以上</strong>(根据 Anthropic 的基准测试)。</p><h3 id="开源生态的快速崛起"><a href="#开源生态的快速崛起" class="headerlink" title="开源生态的快速崛起"></a>开源生态的快速崛起</h3><p>截至2025年底,MCP 官方已收录超过 <strong>120个社区服务器实现</strong>,覆盖:</p><ul><li><strong>数据存储</strong>:PostgreSQL、MongoDB、Redis、S3</li><li><strong>开发工具</strong>:GitHub、GitLab、Docker、Kubernetes</li><li><strong>生产力</strong>:Slack、Google Workspace、Notion、Linear</li><li><strong>IoT 与硬件</strong>:智能家居设备、传感器数据</li></ul><h3 id="对国产-AI-生态的启示"><a href="#对国产-AI-生态的启示" class="headerlink" title="对国产 AI 生态的启示"></a>对国产 AI 生态的启示</h3><p>中国大模型厂商如百度文心一言、阿里通义千问、智谱 GLM 等也在积极探索类似的标准协议。虽然目前还没有完全对标 MCP 的统一方案,但行业趋势已经明确:<strong>AI 时代的竞争不仅是模型的竞争,更是生态连接能力的竞争</strong>。</p><h2 id="展望:从连接协议到-AI-Agent-的基石"><a href="#展望:从连接协议到-AI-Agent-的基石" class="headerlink" title="展望:从连接协议到 AI Agent 的基石"></a>展望:从连接协议到 AI Agent 的基石</h2><p>MCP 的意义远不止于”让 AI 能调用工具”。它的三层抽象(资源、工具、提示词)为 <strong>Agentic AI</strong>(智能体架构)提供了天然的底层支撑——Agent 本质上就是在资源中获取上下文、通过工具执行动作、利用 Prompt 模板优化决策循环的过程。</p><p>未来我们可能会看到:</p><ul><li><strong>跨平台的 MCP 市场</strong>:类似 Docker Hub,用户可以发现、分享和订阅第三方 MCP 服务器</li><li><strong>MCP 2.0 的安全增强</strong>:细粒度权限控制、审计日志、沙箱隔离等企业级特性</li><li><strong>与 Agent 框架的深度整合</strong>:LangChain、AutoGen、LlamaIndex 等主流框架将 MCP 作为默认协议</li></ul><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>Anthropic 的 MCP 协议正在重新定义 AI 应用的基础设施层。它不是又一个”更好的 API SDK”,而是试图建立一套类似于 TCP/IP 或 USB-C 的标准——让不同厂商的 AI 模型、工具和数据源能够无缝协作。</p><p>对于开发者而言,现在正是学习和拥抱 MCP 的最佳时机。当 AI 应用的边界从”模型能力”扩展到”生态连接”时,谁先掌握这套新语言的语法,谁就掌握了下一轮 AI 创新的钥匙。</p><blockquote><p><strong>延伸阅读</strong>:<a href="https://modelcontextprotocol.io/">MCP 官方规范</a>、<a href="https://www.anthropic.com/news/model-context-protocol">Anthropic MCP Blog</a></p></blockquote>]]></content>
<summary type="html"><h2 id="背景:AI-时代的”USB-C”革命"><a href="#背景:AI-时代的”USB-C”革命" class="headerlink" title="背景:AI 时代的”USB-C”革命"></a>背景:AI 时代的”USB-C”革命</h2><p>如果说大语言</summary>
<category term="Tech前沿" scheme="http://coderedeng.github.io/categories/Tech%E5%89%8D%E6%B2%BF/"/>
<category term="AI前沿" scheme="http://coderedeng.github.io/tags/AI%E5%89%8D%E6%B2%BF/"/>
<category term="MCP" scheme="http://coderedeng.github.io/tags/MCP/"/>
</entry>
<entry>
<title>使用 net/http 实现并发爬取多个 url 标题</title>
<link href="http://coderedeng.github.io/2024/04/30/Go%E7%88%AC%E8%99%AB%20-%20%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0%E5%B9%B6%E5%8F%91%E7%88%AC%E5%8F%96%E5%A4%9A%E4%B8%AAurl%E6%A0%87%E9%A2%98/"/>
<id>http://coderedeng.github.io/2024/04/30/Go%E7%88%AC%E8%99%AB%20-%20%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0%E5%B9%B6%E5%8F%91%E7%88%AC%E5%8F%96%E5%A4%9A%E4%B8%AAurl%E6%A0%87%E9%A2%98/</id>
<published>2024-04-30T13:26:38.000Z</published>
<updated>2026-06-07T01:21:54.895Z</updated>
<content type="html"><![CDATA[<h1 id="1-net-x2F-http-包相关方法"><a href="#1-net-x2F-http-包相关方法" class="headerlink" title="1. net/http 包相关方法"></a>1. net/http 包相关方法</h1><h2 id="1-1-http-NewRequestWithContext"><a href="#1-1-http-NewRequestWithContext" class="headerlink" title="1.1 http.NewRequestWithContext"></a>1.1 <code>http.NewRequestWithContext</code></h2><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go">req<span class="token punctuation">,</span> err <span class="token operator">:=</span> http<span class="token punctuation">.</span><span class="token function">NewRequestWithContext</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> <span class="token string">"GET"</span><span class="token punctuation">,</span> url<span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div></figure><ul><li>这个方法用于创建一个新的 HTTP 请求。</li><li>它接受一个 <code>context.Context</code> 对象,可以用来设置请求的超时、取消等操作。</li><li>第一个参数是 HTTP 方法,这里是 “GET”。</li><li>第二个参数是要请求的 URL。</li><li>第三个参数是请求体,这里传入 <code>nil</code> 表示没有请求体。</li><li>返回一个 <code>*http.Request</code> 对象和错误对象。</li></ul><h2 id="1-2-Request-结构体类型"><a href="#1-2-Request-结构体类型" class="headerlink" title="1.2 Request 结构体类型"></a>1.2 <code>Request</code> 结构体类型</h2><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">type</span> Request <span class="token keyword">struct</span> <span class="token punctuation">{</span> Method <span class="token builtin">string</span> <span class="token comment">// 指定HTTP方法(GET,POST,PUT等)。</span> URL <span class="token operator">*</span>url<span class="token punctuation">.</span>URL <span class="token operator">...</span><span class="token operator">...</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="1-3-http-DefaultClient-Do"><a href="#1-3-http-DefaultClient-Do" class="headerlink" title="1.3 http.DefaultClient.Do"></a>1.3 <code>http.DefaultClient.Do</code></h2><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go">resp<span class="token punctuation">,</span> err <span class="token operator">:=</span> http<span class="token punctuation">.</span>DefaultClient<span class="token punctuation">.</span><span class="token function">Do</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div></figure><ul><li><code>http.DefaultClient</code> 是一个全局的 <code>*http.Client</code> 对象,它提供了默认的 HTTP 客户端实现。</li><li><code>Do</code> 方法用于发送 HTTP 请求并返回响应。</li><li>它接受一个 <code>*http.Request</code> 对象作为参数,表示要发送的请求。</li><li>返回一个 <code>*http.Response</code> 对象和一个错误对象。</li></ul><h2 id="1-4-Response-结构体类型"><a href="#1-4-Response-结构体类型" class="headerlink" title="1.4 Response 结构体类型"></a>1.4 <code>Response</code> 结构体类型</h2><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">type</span> Response <span class="token keyword">struct</span> <span class="token punctuation">{</span> Status <span class="token builtin">string</span> <span class="token comment">// e.g. "200 OK"</span> StatusCode <span class="token builtin">int</span> <span class="token comment">// e.g. 200</span> Proto <span class="token builtin">string</span> <span class="token comment">// e.g. "HTTP/1.0"</span> ProtoMajor <span class="token builtin">int</span> <span class="token comment">// e.g. 1</span> ProtoMinor <span class="token builtin">int</span> <span class="token comment">// e.g. 0</span> <span class="token operator">...</span><span class="token operator">...</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="1-5-http-Response"><a href="#1-5-http-Response" class="headerlink" title="1.5 http.Response"></a>1.5 <code>http.Response</code></h2><ul><li><code>http.Response</code> 结构表示 HTTP 响应。</li><li>它包含响应状态码、响应头和响应体等信息。</li><li>在代码中,我们使用 <code>resp.StatusCode</code> 来检查响应的状态码是否为200,以确定请求是否成功。</li></ul><h2 id="1-6-http-Response-Body"><a href="#1-6-http-Response-Body" class="headerlink" title="1.6 http.Response.Body"></a>1.6 <code>http.Response.Body</code></h2><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">defer</span> resp<span class="token punctuation">.</span>Body<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div></figure><ul><li><code>Body</code> 字段是一个 <code>io.ReadCloser</code> 接口,代表响应体。</li><li>在读取完响应体后,我们应该关闭响应体以释放资源。通常使用 <code>defer</code> 关键字来确保在函数退出时关闭响应体。</li></ul><h1 id="2-golang-org-x-net-html-包相关方法"><a href="#2-golang-org-x-net-html-包相关方法" class="headerlink" title="2. golang.org/x/net/html 包相关方法"></a>2. <code> golang.org/x/net/html</code> 包相关方法</h1><h2 id="2-1-html-Parse"><a href="#2-1-html-Parse" class="headerlink" title="2.1 html.Parse"></a>2.1 <code>html.Parse</code></h2><ul><li><code>func Parse(r io.Reader) (*Node, error)</code></li><li>此函数接受一个实现了 <code>io.Reader</code> 接口的对象作为参数,通常是一个 <code>http.Response.Body</code> 或文件等。</li><li>返回一个 <code>*html.Node</code> 对象和一个 <code>error</code>,表示解析的根节点以及可能发生的错误。</li></ul><h2 id="2-2-html-Render"><a href="#2-2-html-Render" class="headerlink" title="2.2 html.Render"></a>2.2 <code>html.Render</code></h2><ul><li><code>func Render(w io.Writer, n *Node) error</code></li><li>此函数接受一个实现了 <code>io.Writer</code> 接口的对象以及一个 <code>*html.Node</code> 对象作为参数,将HTML节点 n 以HTML格式写入 w。</li><li>返回一个 <code>error</code>,表示可能发生的写入错误。</li></ul><h2 id="2-3-html-ParseFragment"><a href="#2-3-html-ParseFragment" class="headerlink" title="2.3 html.ParseFragment"></a>2.3 <code>html.ParseFragment</code></h2><ul><li><code>func ParseFragment(r io.Reader, context *Node) ([]*Node, error)</code></li><li>此函数接受一个实现了 <code>io.Reader</code> 接口的对象以及一个上下文节点 <code>*html.Node</code> 对象作为参数。</li><li>返回解析的HTML片段中的节点切片和一个 <code>error</code>。</li></ul><h2 id="2-4-html-EscapeString"><a href="#2-4-html-EscapeString" class="headerlink" title="2.4 html.EscapeString"></a>2.4 <code>html.EscapeString</code></h2><ul><li><code>func EscapeString(s string) string</code></li><li>此函数接受一个HTML字符串作为参数,返回其在HTML中的转义形式。</li></ul><h2 id="2-5-html-UnescapeString"><a href="#2-5-html-UnescapeString" class="headerlink" title="2.5 html.UnescapeString"></a>2.5 <code>html.UnescapeString</code></h2><ul><li><code>func UnescapeString(s string) string</code></li><li>此函数接受一个转义过的HTML字符串作为参数,返回其原始形式。</li></ul><h2 id="2-6-html-Node"><a href="#2-6-html-Node" class="headerlink" title="2.6 html.Node"></a>2.6 <code>html.Node</code></h2><ul><li>HTML文档中的节点表示。</li><li>每个节点都有一个类型、一系列属性和子节点。</li><li>可以通过 <code>Type</code> 字段来判断节点的类型,如 <code>ElementNode</code>、<code>TextNode</code> 等。</li><li>可以通过 <code>Data</code> 字段获取节点的数据,如元素节点的标签名或文本节点的内容。</li><li>可以通过 <code>Attr</code> 字段获取节点的属性。</li></ul><h1 id="3-具体实现代码"><a href="#3-具体实现代码" class="headerlink" title="3. 具体实现代码"></a>3. 具体实现代码</h1><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"context"</span><span class="token string">"fmt"</span><span class="token string">"net/http"</span><span class="token string">"os"</span><span class="token string">"sync"</span><span class="token string">"time"</span><span class="token string">"golang.org/x/net/html"</span><span class="token punctuation">)</span><span class="token comment">// fetchTitle 使用给定的URL获取网站的标题。</span><span class="token keyword">func</span> <span class="token function">fetchTitle</span><span class="token punctuation">(</span>ctx context<span class="token punctuation">.</span>Context<span class="token punctuation">,</span> url <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>startTime <span class="token operator">:=</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">(</span><span class="token punctuation">)</span>req<span class="token punctuation">,</span> err <span class="token operator">:=</span> http<span class="token punctuation">.</span><span class="token function">NewRequestWithContext</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> <span class="token string">"GET"</span><span class="token punctuation">,</span> url<span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span><span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">,</span> err<span class="token punctuation">}</span>resp<span class="token punctuation">,</span> err <span class="token operator">:=</span> http<span class="token punctuation">.</span>DefaultClient<span class="token punctuation">.</span><span class="token function">Do</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span><span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">,</span> err<span class="token punctuation">}</span><span class="token keyword">defer</span> resp<span class="token punctuation">.</span>Body<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">if</span> resp<span class="token punctuation">.</span>StatusCode <span class="token operator">!=</span> http<span class="token punctuation">.</span>StatusOK <span class="token punctuation">{</span><span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">,</span> fmt<span class="token punctuation">.</span><span class="token function">Errorf</span><span class="token punctuation">(</span><span class="token string">"bad status: %s"</span><span class="token punctuation">,</span> resp<span class="token punctuation">.</span>Status<span class="token punctuation">)</span><span class="token punctuation">}</span>doc<span class="token punctuation">,</span> err <span class="token operator">:=</span> html<span class="token punctuation">.</span><span class="token function">Parse</span><span class="token punctuation">(</span>resp<span class="token punctuation">.</span>Body<span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span><span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">,</span> err<span class="token punctuation">}</span><span class="token keyword">var</span> title <span class="token builtin">string</span><span class="token keyword">var</span> f <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token operator">*</span>html<span class="token punctuation">.</span>Node<span class="token punctuation">)</span>f <span class="token operator">=</span> <span class="token keyword">func</span><span class="token punctuation">(</span>n <span class="token operator">*</span>html<span class="token punctuation">.</span>Node<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> n<span class="token punctuation">.</span>Type <span class="token operator">==</span> html<span class="token punctuation">.</span>ElementNode <span class="token operator">&&</span> n<span class="token punctuation">.</span>Data <span class="token operator">==</span> <span class="token string">"title"</span> <span class="token operator">&&</span> n<span class="token punctuation">.</span>FirstChild <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>title <span class="token operator">=</span> n<span class="token punctuation">.</span>FirstChild<span class="token punctuation">.</span>Data<span class="token punctuation">}</span><span class="token keyword">for</span> c <span class="token operator">:=</span> n<span class="token punctuation">.</span>FirstChild<span class="token punctuation">;</span> c <span class="token operator">!=</span> <span class="token boolean">nil</span><span class="token punctuation">;</span> c <span class="token operator">=</span> c<span class="token punctuation">.</span>NextSibling <span class="token punctuation">{</span><span class="token function">f</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token function">f</span><span class="token punctuation">(</span>doc<span class="token punctuation">)</span>elapsedTime <span class="token operator">:=</span> time<span class="token punctuation">.</span><span class="token function">Since</span><span class="token punctuation">(</span>startTime<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Round</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond<span class="token punctuation">)</span><span class="token keyword">return</span> title <span class="token operator">+</span> <span class="token string">" ("</span> <span class="token operator">+</span> elapsedTime<span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">}</span><span class="token comment">// crawlURLs 并发地爬取一系列URL的标题。</span><span class="token keyword">func</span> <span class="token function">crawlURLs</span><span class="token punctuation">(</span>ctx context<span class="token punctuation">.</span>Context<span class="token punctuation">,</span> urls <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 使用WaitGroup等待所有的goroutine完成</span><span class="token keyword">var</span> wg sync<span class="token punctuation">.</span>WaitGroupwg<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token function">len</span><span class="token punctuation">(</span>urls<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">// 使用通道来收集结果(防止结果竟态)</span>titles <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>urls<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> url <span class="token operator">:=</span> <span class="token keyword">range</span> urls <span class="token punctuation">{</span> <span class="token comment">// 每一个url创建一个goroutine</span><span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span>url <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">defer</span> wg<span class="token punctuation">.</span><span class="token function">Done</span><span class="token punctuation">(</span><span class="token punctuation">)</span>title<span class="token punctuation">,</span> err <span class="token operator">:=</span> <span class="token function">fetchTitle</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> url<span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"Error fetching %s: %v\n"</span><span class="token punctuation">,</span> url<span class="token punctuation">,</span> err<span class="token punctuation">)</span>titles <span class="token operator"><-</span> <span class="token string">"Error: "</span> <span class="token operator">+</span> err<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">return</span><span class="token punctuation">}</span><span class="token comment">// 将标题发送到通道</span>titles <span class="token operator"><-</span> title<span class="token punctuation">}</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 等待所有的goroutine完成</span>wg<span class="token punctuation">.</span><span class="token function">Wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token function">close</span><span class="token punctuation">(</span>titles<span class="token punctuation">)</span><span class="token comment">// 将通道的结果收集到数组中</span>resultTitles <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>urls<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">for</span> title <span class="token operator">:=</span> <span class="token keyword">range</span> titles <span class="token punctuation">{</span>resultTitles <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>resultTitles<span class="token punctuation">,</span> title<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">return</span> resultTitles<span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>urls <span class="token operator">:=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token string">"https://www.baidu.com"</span><span class="token punctuation">,</span><span class="token string">"https://www.36kr.com"</span><span class="token punctuation">,</span><span class="token string">"https://www.sina.com.cn"</span><span class="token punctuation">,</span><span class="token string">"https://www.jd.com"</span><span class="token punctuation">,</span><span class="token string">"https://www.taobao.com"</span><span class="token punctuation">,</span><span class="token string">"https://www.pinduoduo.com"</span><span class="token punctuation">,</span><span class="token string">"https://www.tmall.com"</span><span class="token punctuation">,</span><span class="token string">"https://www.zhihu.com"</span><span class="token punctuation">,</span><span class="token string">"http://www.juejin.cn"</span><span class="token punctuation">,</span><span class="token string">"https://www.aliyun.com"</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token comment">// 创建一个上下文,例如,用于设置超时</span>ctx<span class="token punctuation">,</span> cancel <span class="token operator">:=</span> context<span class="token punctuation">.</span><span class="token function">WithTimeout</span><span class="token punctuation">(</span>context<span class="token punctuation">.</span><span class="token function">Background</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token operator">*</span>time<span class="token punctuation">.</span>Second<span class="token punctuation">)</span><span class="token keyword">defer</span> <span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>titles<span class="token punctuation">,</span> err <span class="token operator">:=</span> <span class="token function">crawlURLs</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> urls<span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Error:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>os<span class="token punctuation">.</span><span class="token function">Exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">for</span> i<span class="token punctuation">,</span> title <span class="token operator">:=</span> <span class="token keyword">range</span> titles <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"%d: %s\n"</span><span class="token punctuation">,</span> i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">,</span> title<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure>]]></content>
<summary type="html"><h1 id="1-net-x2F-http-包相关方法"><a href="#1-net-x2F-http-包相关方法" class="headerlink" title="1. net&#x2F;http 包相关方法"></a>1. net&#x2F;http 包相关方法</</summary>
<category term="Go爬虫" scheme="http://coderedeng.github.io/categories/Go%E7%88%AC%E8%99%AB/"/>
<category term="Go爬虫" scheme="http://coderedeng.github.io/tags/Go%E7%88%AC%E8%99%AB/"/>
</entry>
<entry>
<title>colly</title>
<link href="http://coderedeng.github.io/2024/04/30/Go%E7%88%AC%E8%99%AB%20-%20colly/"/>
<id>http://coderedeng.github.io/2024/04/30/Go%E7%88%AC%E8%99%AB%20-%20colly/</id>
<published>2024-04-30T12:12:11.000Z</published>
<updated>2026-06-07T01:21:54.895Z</updated>
<content type="html"><![CDATA[<p>Colly 是 Go 语言中一个功能强大的爬虫库,它被设计用于简化 Web 页面的抓取和数据提取过程。下面是关于 Colly 的一些主要特点和用法:</p><ol><li><strong>简单易用</strong>:Colly 提供了一个简洁的 API,使得编写爬虫变得非常容易。你可以很容易地定义需要爬取的网站的规则,并提取感兴趣的数据。</li><li><strong>灵活的规则定义</strong>:你可以定义多个规则来匹配不同类型的网页,并在每个规则中指定需要采取的操作,例如提取数据或者跟踪链接。</li><li><strong>并发支持</strong>:Colly 内置了对并发的支持,可以同时爬取多个页面,从而提高爬取效率。</li><li><strong>中间件</strong>:Colly 提供了中间件机制,允许你在请求发送、响应接收等各个阶段添加自定义逻辑,从而灵活地扩展爬虫的功能。</li><li><strong>内置的数据提取工具</strong>:Colly 提供了一些方便的工具函数,用于从 HTML 页面中提取数据,例如使用 CSS 选择器或者 XPath。</li><li><strong>可扩展性</strong>:Colly 的设计非常灵活,你可以根据自己的需求轻松地扩展和定制功能。</li></ol><p>以下是一个爬取微博热搜的示例代码:</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"log"</span><span class="token string">"strings"</span><span class="token string">"github.com/gocolly/colly/v2"</span><span class="token string">"github.com/gocolly/colly/v2/extensions"</span><span class="token punctuation">)</span><span class="token comment">// 获取微博热搜榜colly</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>c <span class="token operator">:=</span> colly<span class="token punctuation">.</span><span class="token function">NewCollector</span><span class="token punctuation">(</span><span class="token punctuation">)</span>extensions<span class="token punctuation">.</span><span class="token function">RandomUserAgent</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span>c<span class="token punctuation">.</span><span class="token function">OnRequest</span><span class="token punctuation">(</span><span class="token keyword">func</span><span class="token punctuation">(</span>r <span class="token operator">*</span>colly<span class="token punctuation">.</span>Request<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 向请求头添加 cookie 防止进入访客模式</span>r<span class="token punctuation">.</span>Headers<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token string">"cookie"</span><span class="token punctuation">,</span> <span class="token string">"SUB=_2AkMRY4uTf8NxqwFRmfsdxWLna410ygHEieKnP3pIJRMxHRl-yT9kqkAvtRB6OuOlexrgRHkeY_A2VqgX2CcV_p0455qS; SUBP=0033WrSXqPxfM72-Ws9jqgMF55529P9D9WhOnHVoAxngUau7LDxX9KO_; _s_tentry=passport.weibo.com; Apache=6010347679488.02.1715406001552; SINAGLOBAL=6010347679488.02.1715406001552; ULV=17154060015601116010347679488.02.1715406001552"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// 解析热搜页面HTML结构,获取相应热搜内容</span>c<span class="token punctuation">.</span><span class="token function">OnHTML</span><span class="token punctuation">(</span><span class="token string">".data table tbody"</span><span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>e <span class="token operator">*</span>colly<span class="token punctuation">.</span>HTMLElement<span class="token punctuation">)</span> <span class="token punctuation">{</span> startTime <span class="token operator">:=</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">(</span><span class="token punctuation">)</span>e<span class="token punctuation">.</span><span class="token function">ForEach</span><span class="token punctuation">(</span><span class="token string">"tr"</span><span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>i <span class="token builtin">int</span><span class="token punctuation">,</span> tr <span class="token operator">*</span>colly<span class="token punctuation">.</span>HTMLElement<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> i <span class="token operator">!=</span> <span class="token number">0</span> <span class="token punctuation">{</span> <span class="token comment">// 去除第一个官方宣传内容</span>str <span class="token operator">:=</span> tr<span class="token punctuation">.</span>Textstr1 <span class="token operator">:=</span> strings<span class="token punctuation">.</span><span class="token function">ReplaceAll</span><span class="token punctuation">(</span>str<span class="token punctuation">,</span> <span class="token string">" "</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span>str2 <span class="token operator">:=</span> strings<span class="token punctuation">.</span><span class="token function">ReplaceAll</span><span class="token punctuation">(</span>str1<span class="token punctuation">,</span> <span class="token string">"\n"</span><span class="token punctuation">,</span> <span class="token string">" "</span><span class="token punctuation">)</span><span class="token keyword">if</span> <span class="token operator">!</span>strings<span class="token punctuation">.</span><span class="token function">Contains</span><span class="token punctuation">(</span>str2<span class="token punctuation">,</span> <span class="token string">"•"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 根据•标记去除相应的广告</span>fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"%+v\n"</span><span class="token punctuation">,</span> str2<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span> timeConsum <span class="token operator">:=</span> time<span class="token punctuation">.</span><span class="token function">Since</span><span class="token punctuation">(</span>startTime<span class="token punctuation">)</span> <span class="token comment">// 计算时间耗时</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"总耗时:"</span><span class="token punctuation">,</span> timeConsum<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span>err <span class="token operator">:=</span> c<span class="token punctuation">.</span><span class="token function">Visit</span><span class="token punctuation">(</span><span class="token string">"https://s.weibo.com/top/summary/"</span><span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>log<span class="token punctuation">.</span><span class="token function">Fatalln</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token keyword">return</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure>]]></content>
<summary type="html"><p>Colly 是 Go 语言中一个功能强大的爬虫库,它被设计用于简化 Web 页面的抓取和数据提取过程。下面是关于 Colly 的一些主要特点和用法:</p>
<ol>
<li><strong>简单易用</strong>:Colly 提供了一个简洁的 API,使得编写爬虫变得</summary>
<category term="Go爬虫" scheme="http://coderedeng.github.io/categories/Go%E7%88%AC%E8%99%AB/"/>
<category term="Go爬虫" scheme="http://coderedeng.github.io/tags/Go%E7%88%AC%E8%99%AB/"/>
</entry>
<entry>
<title>Go语言历史版本演进和新特性[持续更新]</title>
<link href="http://coderedeng.github.io/2024/04/10/Go%E8%AF%AD%E8%A8%80%E5%8E%86%E5%8F%B2%E7%89%88%E6%9C%AC%E6%BC%94%E8%BF%9B%E5%92%8C%E6%96%B0%E7%89%B9%E6%80%A7[%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0]/"/>
<id>http://coderedeng.github.io/2024/04/10/Go%E8%AF%AD%E8%A8%80%E5%8E%86%E5%8F%B2%E7%89%88%E6%9C%AC%E6%BC%94%E8%BF%9B%E5%92%8C%E6%96%B0%E7%89%B9%E6%80%A7[%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0]/</id>
<published>2024-04-10T13:34:11.000Z</published>
<updated>2026-06-18T09:22:57.667Z</updated>
<content type="html"><![CDATA[<p>发布总览:<a href="https://go.dev/doc/devel/release">Release History - The Go Programming Language</a></p><h2 id="GO-1-26-新特性"><a href="#GO-1-26-新特性" class="headerlink" title="GO 1.26 新特性"></a>GO 1.26 新特性</h2><p>发布时间:2026-02-10</p><p>官方说明:<a href="https://go.dev/doc/go1.26">Go 1.26 Release Notes - The Go Programming Language</a></p><p><strong>Go 1.26 标志着垃圾回收器架构的重大升级。</strong></p><p>主要特性:</p><ul><li><strong>全新垃圾回收器(Green Tea)</strong>:全新的 GC 实现,显著提升小对象的标记和扫描性能。Green Tea 在硬件支持上实现了额外的 10% GC 开销降低,大幅减少停顿时间。</li><li><strong>更快的 cgo 调用</strong>:减少 Go 与 C 代码之间的转换开销,提升混合编程场景下的性能表现。</li><li><strong>堆基地址随机化(Heap Base Address Randomization)</strong>:增强安全性,防止基于内存布局的攻击。</li><li><strong>实验性 simd/archsimd 包</strong>:提供对 SIMD 指令集的访问能力,加速数值计算和数据处理任务。这是 Go 首次在标准库中引入硬件级向量化支持。</li><li><strong>实验性 runtime/secret 包</strong>:用于安全敏感数据的处理,防止秘密数据被意外泄露到日志或调试信息中。</li><li><strong>类型构造与循环检测简化</strong>:Go 1.26 简化了类型的构造过程,并增强了对递归类型的循环检测能力。这使得某些复杂的泛型定义变得更加清晰和安全。</li></ul><h2 id="GO-1-25-新特性"><a href="#GO-1-25-新特性" class="headerlink" title="GO 1.25 新特性"></a>GO 1.25 新特性</h2><p>发布时间:2025-08-12</p><p>官方说明:<a href="https://go.dev/doc/go1.25">Go 1.25 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li><strong>更快的切片分配</strong>:编译器现在可以在更多情况下将切片的底层存储分配到栈上,减少堆分配次数,提升性能并降低 GC 压力。</li><li><strong>稳定的 Profile-Guided Optimization(PGO)</strong>:Go 1.24 引入的实验性 PGO 在 Go 1.25 中变为稳定功能,编译器能够根据运行时的 profile 数据自动优化代码路径。</li><li><strong>Swiss Table Map 内部实现</strong>:Go 1.25 进一步提升了 map 性能,采用更先进的 Swiss table 哈希表算法,在大规模 map 操作上性能提升显著。</li><li><strong>改进的 slice 操作</strong>:编译器对 slices.Min、slices.Max、slices.MinMax 等函数的内联优化更加激进,消除了额外的函数调用开销。</li><li><strong>工具链持续增强</strong>:<code>go build</code>、<code>go vet</code> 和 <code>go test</code> 的性能进一步提升,特别是大型项目的构建速度有显著改善。</li></ul><h2 id="GO-1-24-新特性"><a href="#GO-1-24-新特性" class="headerlink" title="GO 1.24 新特性"></a>GO 1.24 新特性</h2><p>发布时间:2025-02-11</p><p>官方说明:<a href="https://go.dev/doc/go1.24">Go 1.24 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li><strong>泛型类型别名正式稳定</strong>:在 Go 1.23 实验性支持的基础上,Go 1.24 使泛型类型别名成为正式语言特性。现在可以定义带参数的类型别名如 <code>type IntSet[T ~int] = map[T]int</code>,极大简化了泛型代码的抽象表达。</li><li><strong>Weak Pointers(弱指针)</strong>:通过 <code>sync/weakpointer</code> 包引入生产级弱指针 API。弱指针允许创建对对象的”软引用”——当唯一强引用被释放时,垃圾回收器会先调用清理函数再回收对象。这对于构建高效的缓存、连接池等场景至关重要。</li><li><strong>SetFinalizerWithCleanup</strong>:新增 <code>runtime.SetFinalizerWithCleanup</code> 函数,在对象被回收前执行清理逻辑后再真正释放内存,替代了原来的 SetFinalizer 方案。</li><li><strong>更快的 Map 实现(Swiss Table)</strong>:Go 1.24 引入基于 Swiss table 算法的新 map 内部实现,相比旧版性能提升可达 30%+,尤其在大规模并发读写场景下优势明显。</li><li><strong>改进的 Benchmark 工具</strong>:<code>go test -bench</code> 提供了更精细的控制和更准确的基准测试结果。</li></ul><h2 id="GO-1-23-新特性"><a href="#GO-1-23-新特性" class="headerlink" title="GO 1.23 新特性"></a>GO 1.23 新特性</h2><p>发布时间:2025-02-07</p><p>官方说明:<a href="https://go.dev/doc/go1.23">Go 1.23 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li><p><strong>迭代器(Iterators)正式加入语言</strong>:这是 Go 1.23 最重量级的新特性。通过 <code>range-over-func</code> 模式,Go 首次原生支持自定义迭代器:</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">type</span> Iterator<span class="token punctuation">[</span>Y any<span class="token punctuation">]</span> <span class="token keyword">func</span><span class="token punctuation">(</span>yield <span class="token keyword">func</span><span class="token punctuation">(</span>Y<span class="token punctuation">)</span> <span class="token builtin">bool</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div></figure><p>这使得 for-range 可以用于遍历树、链表、生成器等自定义数据结构,无需手动维护状态指针。例如可以优雅地实现树的深度优先遍历、无限序列生成等。</p></li><li><p><strong>泛型类型别名实验性支持</strong>:Go 1.23 引入对带参数的类型别名的实验性支持,允许定义如 <code>type IntSet[K ~int] = map[K]int</code> 这样的泛型类型别名,为后续正式化铺平道路。</p></li><li><p><strong>Timer 和 Ticker 的重大优化</strong>:</p><ul><li>改进的 GC 机制防止内存泄漏问题</li><li>Timer/Ticker 在调用 Reset() 或 Stop() 后不再向通道发送旧数据,提高了定时器操作的安全性和可靠性</li></ul></li><li><p><strong>slices 包扩展</strong>:新增 <code>Min</code>、<code>Max</code>、<code>MinMax</code> 等实用函数,配合泛型使切片操作更加简洁。</p></li><li><p><strong>Make[T] 函数</strong>:对任何可比较类型 T,可以通过 <code>Make[T](value)</code> 生成对该值规范副本的引用 Handle[T]。Handle[T] 之间的高效指针比较可用于去重和内存优化。</p></li></ul><h2 id="GO-1-22-新特性"><a href="#GO-1-22-新特性" class="headerlink" title="GO 1.22 新特性"></a>GO 1.22 新特性</h2><p>发布时间:2024-02-06</p><p>官方说明:<a href="https://go.dev/doc/go1.22">Go 1.22 Release Notes - The Go Programming Language</a></p><ul><li><p>循环变量改进:Go 1.22解决了for循环中循环变量在迭代之间意外共享的问题。在新的版本中,for循环中的循环变量(如for range语句中的变量)将不再在整个循环中共享,而是在每次迭代中都有自己的变量。这意味着在goroutine中使用循环变量时,每个goroutine将捕获其迭代的变量,而不是共享同一个变量。这一变化可能会对现有代码的行为产生影响,因此Go团队提供了一个工具来检测代码中可能因此特性变化而产生问题的地方。</p></li><li><p>range支持整型表达式:在Go 1.22中,for range循环的range表达式除了支持传统的数组、切片、map、channel等类型外,还支持整型表达式。这意味着你可以在for range循环中使用整型值,循环将基于该整型值进行迭代。</p></li><li><p>性能提升:Go 1.22在运行时进行了内存优化,提高了CPU性能(约1-3%),并减少了大多数Go程序的内存开销(约1%)。此外,Go 1.21引入的profile-guided optimization(PGO)功能在1.22版本中得到了进一步改进,包括改进的devirtualization,允许更多的接口方法调用进行静态调度,从而提高了程序性能。</p></li><li><p>标准库新增内容:</p><ul><li>引入了一个新的<code>math/rand/v2</code>包,提供更清晰、更一致的API,并使用更高质量、更快的伪随机生成算法。</li><li><code>net/http.ServeMux</code>的 patterns 现在接受方法和通配符,例如可以匹配仅限GET请求的<code>GET /task/{id}/</code>模式。</li><li><code>database/sql</code>包中新增了一个<code>Null[T]</code>类型,用于扫描可为空的列。</li><li>在<code>slices</code>包中添加了一个<code>Concat</code>函数,用于连接任意类型的多个切片。</li></ul></li><li><p>工具链:</p><p>在Go工具链改善方面,首当其冲的要数go module相关工具了。</p><p>在Go 1.22中,go work增加了一个与go mod一致的特性:支持vendor。通过go work vendor,可以将workspace中的依赖放到vendor目录下,同时在构建时,如果module root下有vendor目录,那么默认的构建是go build -mod=vendor,即基于vendor的构建。</p><p>go mod init在Go 1.22中将不再考虑GOPATH时代的包依赖工具的配置文件了,比如Gopkg.lock。在Go 1.22版本之前,如果go module之前使用的是类似<a href="https://tonybai.com/2017/06/08/first-glimpse-of-dep/">dep这样的工具来管理包依赖</a>,go mod init会尝试读取dep配置文件来生成go.mod。</p><p>go vet工具取消了对loop变量引用的警告,增加了对空append的行为的警告(比如:slice = append(slice))、增加了deferring time.Since的警告以及在log/slog包的方法调用时key-value pair不匹配的警告。</p></li></ul><h2 id="GO-1-21-新特性"><a href="#GO-1-21-新特性" class="headerlink" title="GO 1.21 新特性"></a>GO 1.21 新特性</h2><p>发布时间:2023.08.08</p><p>官方说明:<a href="https://go.dev/doc/go1.21">Go 1.21 Release Notes - The Go Programming Language</a></p><p>特性:</p><p>go1.21.1(发布于 2023 年 9 月 6 日)包括对<code>cmd/go</code>、<code>crypto/tls</code>和<code>html/template</code>包的四个安全修复,以及对编译器、<code>go</code>命令、链接器、运行时和<code>context</code>、<code>crypto/tls</code>、<code>encoding/gob</code>、<code>encoding/xml</code>、<code>go/types</code>、<code>net/http</code>、<code>os</code>和 的错误修复<code>path/filepath</code>包。</p><p>go1.21.2(2023 年 10 月 5 日发布)包括对包的一项安全修复<code>cmd/go</code>,以及对编译器、<code>go</code>命令、链接器、运行时和包的错误修复<code>runtime/metrics</code>. </p><p>go1.21.3(2023 年 10 月 10 日发布)包含对该<code>net/http</code>软件包的安全修复。</p><h2 id="GO-1-20-新特性"><a href="#GO-1-20-新特性" class="headerlink" title="GO 1.20 新特性"></a>GO 1.20 新特性</h2><p>发布时间:2023.02.01</p><p>官方说明:<a href="https://go.dev/doc/go1.20">Go 1.20 Release Notes - The Go Programming Language</a></p><p>特性:</p><ul><li>支持将slice直接转为数组</li><li>Comparable类型可比较</li><li>unsafe包添加<code>Slice</code>,<code>SliceData</code>,<code>String</code>,<code>StringData 4个函数</code></li><li>可移植性:Go 1.20将会成为支持macOS 10.13 High Sierra和10.14 Mojave的最后一个版本。</li><li>Go 1.20增加了对于RISC-V架构在FreeBSD操作系统的实验性支持</li><li>PGO引入</li><li>标准库加强<ul><li>新增了几个 时间转换格式常量</li><li>新包 crypto/ecdh 支持通过 NIST 曲线和 Curve25519 椭圆曲线 Diffie-Hellman 密钥交换</li><li>新类型 http.ResponseController 访问 http.ResponseWriter 接口未处理的扩展请求</li><li>httputil.ReverseProxy 包含一个新的 Rewrite 钩子函数,取代了之前的 Director 钩子</li><li>新方法 context.WithCancelCause 提供了一种方法来取消具有给定错误的上下文</li><li>os/exec.Cmd 结构体中的新字段 Cancel 和 WaitDelay, 指定 Cmd 在其关联的 Context 被取消或其进程退出时的回调</li></ul></li><li>工具链<ul><li>cover 工具可以收集整个程序的覆盖率,不仅仅是单元测试</li><li>go build、go install 和其他与构建相关的命令可以接收一个 -pgo 标志,启用配置文件引导优化,以及一个 -cover 标志,用于整个程序覆盖率分析</li><li>go test -json 的实现已得到改进,可以处理复杂多样的 Stdout 输出</li><li>vet 在并行运行的测试中可能会发生更多循环变量引用错误</li><li>在没有 C 工具链 的系统上默认禁用 CGO</li></ul></li><li>性能提升<ul><li><a href="https://so.csdn.net/so/search?q=%E7%BC%96%E8%AF%91%E5%99%A8&spm=1001.2101.3001.7020">编译器</a>和 GC 的优化减少了内存开销,并将 CPU 性能整体提高了 2%</li><li>针对编译时间进行了优化,提升了 10%。使得构建速度与 Go 1.17 保持一致 (恢复到了泛型之前的速度)</li><li>Go 发行版瘦身,新版本起,Go 的 $GOROOT/pkg 目录将不再存储标准库的预编译包存档,Go 发行版的将迎来一轮瘦身</li></ul></li></ul><h2 id="GO-1-19-新特性"><a href="#GO-1-19-新特性" class="headerlink" title="GO 1.19 新特性"></a>GO 1.19 新特性</h2><p>时间:2022.05</p><p>官方说明:<a href="https://go.dev/doc/go1.19">Go 1.19 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>泛型问题fix</li><li>修订Go memory model:对Go memory model做了更正式的整体描述,增加了对multiword竞态、runtime.SetFinalizer、更多sync类型、atomic操作以及编译器优化方面的描述。</li><li>修订go doc comment格式:增加了对超链、列表、标题、标准库API引用等格式支持</li><li>新增runtime.SetMemoryLimit和GOMEMLIMIT环境变量:避免Go程序因分配heap过多,超出系统内存资源限制而被kill,默认memory limit是math.MaxInt64,limit限制的是go runtime掌控的内存总量,对于开发者自行从os申请的内存(比如通过mmap)则不予考虑。</li><li>启动时将默认提高打开文件的限值:对于导入os包的go程序,Go将在1.19中默认提高这些限制值到hard limit。</li><li>race detector将升级到v3版thread sanitizer:race detector性能相对于上一版将提升1.5倍-2倍,内存开销减半,并且没有对goroutine的数量的上限限制</li><li>增加”unix” build tag://go:build unix</li><li>标准库net包使用EDNS</li><li>标准库flag包增加TextVar函数</li><li>正式支持64位龙芯cpu架构 (GOOS=linux, GOARCH=loong64)</li><li>当Go程序空闲时,Go GC进入到周期性的GC循环的情况下(2分钟一次),Go运行时现在会在idle的操作系统线程上安排更少的GC worker goroutine,减少空闲时Go应用对os资源的占用。</li><li>Go行时将根据goroutine的历史平均栈使用率来分配初始goroutine栈,避免了一些goroutine的最多2倍的goroutine栈空间浪费。</li><li>sync/atomic包增加了新的高级原子类型Bool, Int32, Int64, Uint32, Uint64, Uintptr和Pointer,提升了使用体验。</li><li>Go编译器使用jump table重新实现了针对大整型数和string类型的switch语句,平均性能提升20%左右。</li><li>等</li></ul><h2 id="Go-1-18-新特性"><a href="#Go-1-18-新特性" class="headerlink" title="Go 1.18 新特性"></a>Go 1.18 新特性</h2><p>时间:2022.03</p><p>官方说明:<a href="https://go.dev/doc/go1.18">Go 1.18 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>泛型支持</li><li>Workspaces 工作区</li><li>Go编译器与Go module变化:修正的语法bug,在AMD64平台上引入architectural level,为ARM64架构带来高达 20% 的 CPU 性能改进:但由于编译器中与支持泛型有关的变化,Go 1.18 的编译速度可能比Go 1.17的编译速度大约慢15%。编译后的代码的执行时间不受影响。打算在Go 1.19中提高编译器的速度。Go 1.18明确了能修改go.mod、go.sum的命令只有三个:go get、go mod tidy和go mod download。</li><li>go fuzzing test:将fuzz testing纳入了go test工具链,与单元测试、性能基准测试等一起成为了Go原生测试工具链中的重要成员,单元测试函数名样式:FuzzXxx</li><li>go get 不再执行编译和安装工作</li><li>gofmt支持并发</li><li>内置函数Append对切片的扩容算法发生变化:和Go 1.17以1024作为大小分界不同,Go 1.18使用256作为threshold</li><li>新增net/netip包</li><li>tls client默认将使用TLS 1.2版本</li><li>crypto/x509包默认将拒绝使用SHA-1哈希函数签名的证书(自签发的除外)</li><li>strings包和bytes包新增Cut函数</li><li>runtime/pprof精确性提升</li><li>sync包新增Mutex.TryLock、RWMutex.TryLock和RWMutex.TryRLock</li><li>等</li></ul><h2 id="Go-1-17-新特性"><a href="#Go-1-17-新特性" class="headerlink" title="Go 1.17 新特性"></a>Go 1.17 新特性</h2><p>时间:2021.08</p><p>官方说明:<a href="https://go.dev/doc/go1.17">Go 1.17 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>从切片到数组指针的转换: []T 类型的表达式 s 现在可以转换为数组指针类型 *[N]T</li><li>go modules 支持”修剪模块图”(Pruned module graphs):go mod tidy -go=1.17</li><li>编译器带来了额外的改进:即一种传递函数参数和结果的新方法,程序性能提高了约 5%,amd64 平台的二进制大小减少了约 2%。</li><li>unsafe包新增了<code>unsafe.Add</code>和<code>unsafe.Slice</code></li><li><code>go.mod 中添加 // Deprecated: 注释来弃用模块</code></li><li>net包:</li></ul><ol><li>url参数解析增加对”;”的支持变化(原先 example?a=1;b=2&c=3 会解析成 <code>map[a:[1] b:[2] c:[3]]</code>, 现在解析成<code>map[c:[3]]</code>)</li><li>增加 IP.IsPrivate 判断私有 IP</li><li>a.b.c.d 格式的 ip v4 地址不允许每段有前缀 0(因为某些系统会认为前缀 0 表示 8进制)</li><li>等</li></ol><h2 id="Go-1-16-新特性"><a href="#Go-1-16-新特性" class="headerlink" title="Go 1.16 新特性"></a>Go 1.16 新特性</h2><p>时间:2021.02</p><p>官方说明:<a href="https://go.dev/doc/go1.17">Go 1.16 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>GO111MODULE 默认为 on</li><li>支持编译阶段将静态资源文件打包进编译好的程序中,并提供访问这些文件的能力://go:embed</li></ul><h2 id="Go-1-15-新特性"><a href="#Go-1-15-新特性" class="headerlink" title="Go 1.15 新特性"></a>Go 1.15 新特性</h2><p>时间:2020.08</p><p>官方说明:<a href="https://go.dev/doc/go1.16">Go 1.15 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>改进了对高核心数的小对象的分配</li><li>编译器/汇编器/链接器的优化:二进制大小减少了约 5%,减少了链接器资源的使用(时间和内存)并提高了代码的稳健性/可维护性。</li><li>内置了time/tzdata包:允许将时区数据库嵌入到程序中</li><li>等</li></ul><h2 id="Go-1-14-新特性"><a href="#Go-1-14-新特性" class="headerlink" title="Go 1.14 新特性"></a>Go 1.14 新特性</h2><p>时间:2020.02</p><p>官方说明:<a href="https://go.dev/doc/go1.15">Go 1.14 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>Go Module已可用于生产使用</li><li>嵌入具有重叠方法集的接口</li><li>改进了defer的性能</li><li>goroutines 异步可抢占</li><li>页面分配器更高效</li><li>内部定时器更高效</li><li>等</li></ul><h2 id="Go-1-13-新特性"><a href="#Go-1-13-新特性" class="headerlink" title="Go 1.13 新特性"></a>Go 1.13 新特性</h2><p>时间:2019.09</p><p>官方说明:<a href="https://go.dev/doc/go1.14">Go 1.13 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>优化sync.Pool</li></ul><p>sync 包的 Pool 组件得到改进,得其中的资源不会在垃圾回收时被清除(通过新机制里引入的缓存,两次垃圾回收之间没有被使用过的实例才会被清除)</p><ul><li>重了逃逸分析逻辑,使得 Go 程序减少了堆上的分配次数</li><li>go 命令默认使用 Go module mirror and Go checksum database下载和验证模块</li><li>对数字文字的改进</li><li>错误换行</li><li>默认开启 TLS 1.3</li><li>等</li></ul><h2 id="Go-1-12-新特性"><a href="#Go-1-12-新特性" class="headerlink" title="Go 1.12 新特性"></a>Go 1.12 新特性</h2><p>时间:2019.02</p><p>官方说明:<a href="https://go.dev/doc/go1.13">Go 1.12 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>改进了Go modules</li><li>在<a href="https://link.juejin.cn/?target=https://pkg.go.dev/golang.org/x/tools/go/analysis">analysis包</a>基础上重写了 go vet 命令</li><li>等</li></ul><h2 id="Go-1-11-新特性"><a href="#Go-1-11-新特性" class="headerlink" title="Go 1.11 新特性"></a>Go 1.11 新特性</h2><p>时间:2018.08</p><p>官方说明:<a href="https://go.dev/doc/go1.12">Go 1.11 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>Go modules</li></ul><h2 id="Go-1-10-新特性"><a href="#Go-1-10-新特性" class="headerlink" title="Go 1.10 新特性"></a>Go 1.10 新特性</h2><p>时间:2018.02</p><p>官方说明:<a href="https://go.dev/doc/go1.12">Go 1.10 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>go test with cache:go test命令可以缓存测试结果</li><li>go build 命令会缓存最近构建过的包,从而加快了构建过程</li><li>明确预声明类型(predeclared type)是defined type还是alias type</li><li>移除spec中对method expression: T.m中T的类型的限制</li><li>默认的GOROOT</li><li>增加GOTMPDIR变量</li><li>通过cache实现增量构建,提高go tools性能</li><li>go tool pprof做了一个较大的改变:增加了Web UI</li><li>标准库新增strings.Builder</li><li>标准库bytes包的几个方法Fields, FieldsFunc, Split和SplitAfter在底层实现上有变化,使得外部展现的行为有所变化</li><li>等</li></ul><h2 id="Go-1-9-新特性"><a href="#Go-1-9-新特性" class="headerlink" title="Go 1.9 新特性"></a>Go 1.9 新特性</h2><p>时间:2017.08</p><p>官方说明:<a href="https://go.dev/doc/go1.10">Go 1.9 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>提升了垃圾收集器和编译器</li><li>增加了类型别名</li><li>新增了sync.Map</li><li>time包更加安全</li><li>testing包新增helper方法</li><li>支持渐进式代码重构</li><li>引入了类型别名并提升了运行时和工具支持</li></ul><h2 id="Go-1-8-新特性"><a href="#Go-1-8-新特性" class="headerlink" title="Go 1.8 新特性"></a>Go 1.8 新特性</h2><p>时间:2017.02</p><p>官方说明:<a href="https://go.dev/doc/go1.9">Go 1.8 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>优化编译</li></ul><p>CPU 时间在 32 位 ARM 系统上减少了 20-30%, 还针对 64 位 x86 系统进行了一些适度的性能改进。编译器和<a href="https://so.csdn.net/so/search?q=%E9%93%BE%E6%8E%A5%E5%99%A8&spm=1001.2101.3001.7020">链接器</a>变得更快。</p><p>编译时间应该比 Go 1.7 改进了大约 15%</p><p>Go 1.7中进入标准库的context,提供了取消和超时机制。</p><p>Go 1.8 让标准库中更多package使用(支持)context,包括 database/sql,net 包, net/http 包中的 Server.Shutdown等</p><ul><li>对垃圾回收器改进,使两次垃圾回收的暂停时间减小到了毫秒级</li><li>同时识别了剩余仍未解决的暂停模式,并在下一个版本中得到修复。修复后,通常情况下暂停时间能控制在 100 微秒左右,甚至能低至 10 微秒。</li><li>改进了 defer 函数</li><li>部分标准库使用context包来改造</li><li>sort 包中新添加的 Slice 函数,对切片进行排序变得比之前简单得多</li></ul><h2 id="Go-1-7-新特性"><a href="#Go-1-7-新特性" class="headerlink" title="Go 1.7 新特性"></a>Go 1.7 新特性</h2><p>时间:2016.08</p><p>官方说明:<a href="https://go.dev/doc/go1.8">Go 1.7 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>context包转正</li><li>编译时间显着加快:二进制文件大小减少了 20-30%, CPU 时间减少了 5-35%</li><li>垃圾收集器的加速和标准库的优化</li><li>go tool trace改进</li></ul><h2 id="Go-1-6-新特性"><a href="#Go-1-6-新特性" class="headerlink" title="Go 1.6 新特性"></a>Go 1.6 新特性</h2><p>时间:2016.02</p><p>官方说明:<a href="https://go.dev/doc/go1.7">Go 1.6 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>增加对于 HTTP/2 协议的默认支持</li><li>再一次降低了垃圾回收器的延迟</li><li>runtime改变了打印程序结束恐慌的方式。现在只打印发生panic的 goroutine 的堆栈,而不是所有现有的 goroutine</li><li>默认启用vendor目录</li><li>sort.Sort 内部的算法进行了改进,运行速度提高了约 10%</li></ul><h2 id="Go-1-5-新特性"><a href="#Go-1-5-新特性" class="headerlink" title="Go 1.5 新特性"></a>Go 1.5 新特性</h2><p>时间:2015.08</p><p>官方说明:<a href="https://go.dev/doc/go1.6">Go 1.5 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li><a href="https://link.juejin.cn/?target=https://go.dev/doc/go1.5%23gc">垃圾回收器</a>被完全重新设计实现: 基于并发的回收期,GC延迟显著降低,来自Twitter生产案例从300ms下降到30ms</li><li>调度程序的相关改进允许将默认的 GOMAXPROCS 值(并发执行的 goroutine 的数量)从 1 更改为逻辑 CPU 的数量。在以前的版本中,默认值为 1</li><li>go tool trace:可以在运行时可视化跟踪程序,追踪信息可在测试或运行期间生成,展示在浏览器窗口中</li><li>map语法的更改:由于疏忽,允许从slice literals中省略元素类型的规则未应用于map。在1.5版本得到了修正,以下两种定义map的方式从1.5及之后都可以(即可以省略Point的类型)</li></ul><h2 id="Go-1-4-新特性"><a href="#Go-1-4-新特性" class="headerlink" title="Go 1.4 新特性"></a>Go 1.4 新特性</h2><p>时间:2014.02</p><p>官方说明:<a href="https://go.dev/doc/go1.5">Go 1.4 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li><p>For-range loops支持新语法</p><p>1234567891011121314151617</p><p>package mainimport “fmt”func main() { sli := []string{“shandong”, “zhejiang”, “guangdong”, “jiangsu”} for k, v := range sli { fmt.Println(“k-v:”, k, v) //go 1.3及之前的For-range loops } for range sli { fmt.Println(“从1.4开始这种写法是可以通过编译的”) }}</p></li><li><p>Android 的官方支持包<a href="https://link.juejin.cn/?target=https://github.com/golang/mobile">golang.org/x/mobile</a>随该版本一同发布,使开发者可以仅用 Go 代码编写简单的 Android 应用。</p></li><li><p>之前用 C 和汇编语言编写的大多数运行时已转换为用 Go 语言实现 && 使用了更精准的垃圾收集器,堆栈大小减少了 10~30%</p></li><li><p>发布 go generate 命令,此命令会扫描//go:generate 指令提供的信息生成代码,简化了代码生成的方式。 <a href="https://link.juejin.cn/?target=https://go.dev/blog/generate">Generating code</a></p></li><li><p>引入了Internal包</p></li></ul><p>Go 的项目代码管理工具从 Mercurial 切换为 Git,与此同时,项目也从 Google Code 迁移到了 Github 上</p><h2 id="Go-1-3-新特性"><a href="#Go-1-3-新特性" class="headerlink" title="Go 1.3 新特性"></a>Go 1.3 新特性</h2><p>时间:2014.06</p><p>官方说明:<a href="https://go.dev/doc/go1.4">Go 1.3 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>堆栈管理得到了重要改善</li><li>发布了 sync 包的 Pool 组件</li><li>改进了<a href="https://link.juejin.cn/?target=https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub">channel的实现</a>,提升了性能</li></ul><h2 id="Go-1-2-新特性"><a href="#Go-1-2-新特性" class="headerlink" title="Go 1.2 新特性"></a>Go 1.2 新特性</h2><p>时间:2013.12</p><p>官方说明:<a href="https://go.dev/doc/go1.3">Go 1.2 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li><a href="https://link.juejin.cn/?target=https://go.dev/doc/go1.2%23three_index">Three-index slices</a></li><li>go test 命令支持代码覆盖率报告,并提供新的 <code>go tool cover</code> 命令输出代码测试覆盖率的统计信息. <a href="https://link.juejin.cn/?target=https://go.dev/blog/cover">The cover story</a></li></ul><h2 id="Go-1-1-新特性"><a href="#Go-1-1-新特性" class="headerlink" title="Go 1.1 新特性"></a>Go 1.1 新特性</h2><p>时间:2013.05</p><p>官方说明:<a href="https://go.dev/doc/go1.2">Go 1.1 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>增强语言特性(编译器、垃圾回收机制、映射、goroutine 调度器)与性能。</li></ul><h2 id="Go-1-0-新特性"><a href="#Go-1-0-新特性" class="headerlink" title="Go 1.0 新特性"></a>Go 1.0 新特性</h2><p>时间:2012.03</p><p>官方说明:<a href="https://go.dev/doc/go1">Go 1 Release Notes - The Go Programming Language</a></p><p>主要特性:</p><ul><li>承诺兼容性,确保向后兼容 <a href="https://go.dev/doc/go1compat">Go 1 and the Future of Go Programs - The Go Programming Language</a></li></ul><p>本文转自 <a href="https://blog.csdn.net/mdpets/article/details/127663206%EF%BC%8C%E5%A6%82%E6%9C%89%E4%BE%B5%E6%9D%83%EF%BC%8C%E8%AF%B7%E8%81%94%E7%B3%BB%E5%88%A0%E9%99%A4%E3%80%82">https://blog.csdn.net/mdpets/article/details/127663206,如有侵权,请联系删除。</a></p>]]></content>
<summary type="html"><p>发布总览:<a href="https://go.dev/doc/devel/release">Release History - The Go Programming Language</a></p>
<h2 id="GO-1-26-新特性"><a href="#GO-1</summary>
<category term="Go基础" scheme="http://coderedeng.github.io/categories/Go%E5%9F%BA%E7%A1%80/"/>
<category term="Go基础" scheme="http://coderedeng.github.io/tags/Go%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>并发</title>
<link href="http://coderedeng.github.io/2023/10/20/Go%E8%BF%9B%E9%98%B6%20-%20%E5%B9%B6%E5%8F%91/"/>
<id>http://coderedeng.github.io/2023/10/20/Go%E8%BF%9B%E9%98%B6%20-%20%E5%B9%B6%E5%8F%91/</id>
<published>2023-10-20T12:50:13.000Z</published>
<updated>2026-06-07T01:21:54.904Z</updated>
<content type="html"><![CDATA[<h1 id="1-并发"><a href="#1-并发" class="headerlink" title="1. 并发"></a>1. 并发</h1><h2 id="1-1-并发和并行的区别"><a href="#1-1-并发和并行的区别" class="headerlink" title="1.1 并发和并行的区别"></a>1.1 并发和并行的区别</h2><p>并发和并行是两个不同的概念:</p><ul><li>并行意味着程序在<strong>任意时刻</strong>都是同时运行的;</li><li>并发意味着程序在<strong>单位时间内</strong>是同时运行的</li></ul><h3 id="1-1-1-并行"><a href="#1-1-1-并行" class="headerlink" title="1.1.1 并行"></a>1.1.1 并行</h3><p><strong>并行</strong>就是在任一粒度时间内都具备同时执行的能力:简单来说并行就是多机或多台机器并行处理; SMP(SMP 是对称多处理器(Symmetric MultiProcessing)的简称。在这样的系统中包含多个处理器,同时,处理器间共享了内存和 I/O 总线。”对称”是指所有的处理器在功能和位置上地位相同,不存在主处理器或者被处理器较多的 “主机”) 表面上看是并行的,但由于是共享内存,以及线程间的同步等,不可能完全做到并行。</p><h3 id="1-1-2-并发"><a href="#1-1-2-并发" class="headerlink" title="1.1.2 并发"></a>1.1.2 并发</h3><p><strong>并发</strong>是在规定的时间内多个请求都得到执行和处理,强调的是给外界的感觉,实际上内部可能是分时操作的。并发重在避免阻塞,使程序不会因为一个阻塞而停止处理。并发典型的应用场景:分时操作系统就是一种并发设计(忽略多核 CPU)。</p><h2 id="1-2-goroutine"><a href="#1-2-goroutine" class="headerlink" title="1.2 goroutine"></a>1.2 goroutine</h2><p><code>goroutine</code>是 Go 语言中处理并发执行的一个主要工具,是 Go 运行时层面的轻量级线程,与 OS 线程相比,它的开销更小。操作系统可以进行线程和进程的调度,本身具备并发处理能力,但进程切换代价还是过高,当操作系统在系统进程之间切换时,它需要保存当前正在运行进程的状态,以便在再次切换回该进程时恢复执行。这通常涉及保存进程的 “上下文”,即使该进程能够从中断点继续执行的所有信息(<strong>处理器的寄存器</strong>、<strong>内存管理信息</strong>、<strong>进程状态</strong>、<strong>输入和输出状态</strong>、<strong>资源使用情况</strong>等)。如果应用可以在用户态进行调度,应该可以更大限度地提升程序运行效率,goroutine就是基于这个思想实现的。</p><ul><li>goroutine 示例,代码如下:</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">var</span> wg sync<span class="token punctuation">.</span>WaitGroup <span class="token comment">// 第一步:定义一个计数器</span><span class="token keyword">func</span> <span class="token function">routine1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">10</span><span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"routine1 你好golang-"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span> <span class="token comment">// routine1 你好golang-0, ...9</span> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> wg<span class="token punctuation">.</span><span class="token function">Done</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//协程计数器-1 // 第三步:协程执行完毕,计数器-1</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">routine2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">2</span><span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"routine2 你好golang-"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span> <span class="token comment">// routine2 你好golang-0, routine2 你好golang-1</span> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> wg<span class="token punctuation">.</span><span class="token function">Done</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//协程计数器-1</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> wg<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment">//协程计数器+1 第二步:开启一个协程计数器+1</span> <span class="token keyword">go</span> <span class="token function">routine1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//表示开启一个协程</span> wg<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment">//协程计数器+1</span> <span class="token keyword">go</span> <span class="token function">routine2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//表示开启一个协程</span> wg<span class="token punctuation">.</span><span class="token function">Wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//等待协程执行完毕... 第四步:计数器为0时推出</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"主线程退出..."</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>goroutine 有如下特性:</p><ul><li>go 的执行是非阻塞的,不会等待;</li><li>go 后面函数的返回值会被忽略;</li><li>调度器不能保证多个 goroutine 的执行次序;</li><li>没有父子 goroutine 的概念,所有 goroutine 是平等地被调度和执行的;</li><li>go 程序运行时会在 main 函数先创建一个 goroutine,其他 go 关键字创建的 goroutine 会另外创建;</li><li>go 没有暴露 goroutine id 给用户,所以不能在一个 goroutine 里面显式地操作另一个 goroutine ,不过 runtime 包提供了一些函数访问和设置 goroutine 的相关信息;</li></ul><h3 id="1-2-1-GOMAXPROCS"><a href="#1-2-1-GOMAXPROCS" class="headerlink" title="1.2.1 GOMAXPROCS"></a>1.2.1 GOMAXPROCS</h3><p>GOMAXPROCS( n int ) 用来设置或查询可以并发执行的 goroutine 数目,n 大于 1 表示设置 GOMAXPROCS 值,否则表示查询当前 GOMAXPROCS 的值。</p><h3 id="1-2-2-Goexit"><a href="#1-2-2-Goexit" class="headerlink" title="1.2.2 Goexit"></a>1.2.2 Goexit</h3><p>Goexit() 是结束当前 goroutine 的运行, Goexit 在结束当前 goroutine 运行之前会调用当前 goroutine 已经注册的 defer 。 Goexit 并不会产生 panic ,所以该 goroutine defer 里面的 recover 调用都返回 nil 。</p><h3 id="1-2-3-Gosched"><a href="#1-2-3-Gosched" class="headerlink" title="1.2.3 Gosched"></a>1.2.3 Gosched</h3><p>Gosched() 是放弃当前调度执行机会,将当前 goroutine 放到队列中等待下次被调度。只有 goroutine 还是不够的,多个 goroutine 之间还需要通信、同步、协同等。</p><h2 id="1-3-Chan"><a href="#1-3-Chan" class="headerlink" title="1.3 Chan"></a>1.3 Chan</h2><p>chan 是 Go 语言里面的一个关键宇,是 channel 的简写,翻译为中文就是通道。 goroutine 是 Go 语言里面的并发执行体,通道是 goroutine 之间通信和同步的重要组件。 Go 的哲学是“不要通过共享内存来通信,而是通过通信来共享内存”(CSP(Communicating Sequential Processes)是一种用于设计并发系统的模型,它强调通过在独立的并发实体或“进程”之间传递消息来进行通信),通道是 Go 通过通信来共享内存的载体。例如:</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go">//创建一个无缓冲的通道,通道存放元素的类型为 datatype <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> datatype <span class="token punctuation">)</span> //创建一个有 <span class="token number">10</span> 个缓冲的通道,通道存放元素的类型为 datatype <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> datatype<span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>通道分为无缓冲的通道和有缓冲的通道, Go 提供内置函数 len 和 cap ,<strong>无缓冲的通道的 len</strong> <strong>和 cap 都是 0</strong>,<strong>有缓冲的通道的 len 代表没有被读取的元素数, cap 代表整个通道的容量</strong>。无缓冲的通道既可以用于通信,也可以用于两个 goroutine 的同步,有缓冲的通道主要用于通信。有缓冲通道示例:</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">var</span> m sync<span class="token punctuation">.</span>Mutex<span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>m<span class="token punctuation">.</span><span class="token function">Lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 互斥锁</span>c <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span> <span class="token punctuation">,</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">defer</span> m<span class="token punctuation">.</span><span class="token function">Unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 解锁</span><span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">100</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">{</span>c <span class="token operator"><-</span> i <span class="token comment">// 向 c 通道传递数据</span><span class="token punctuation">}</span><span class="token function">close</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>m<span class="token punctuation">.</span><span class="token function">Lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 等到互斥锁解锁,然后再次锁定用来阻塞主程序。</span><span class="token keyword">for</span> v <span class="token operator">:=</span> <span class="token keyword">range</span> c <span class="token punctuation">{</span> <span class="token comment">// 向已关闭的通道遍历读取数据</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>v<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>写到缓冲通道中的数据不会消失,它还可以缓冲和适配两个 goroutine 处理速率不一致的情况,缓冲通道和消息队列类似,有削峰和增大吞吐量的功能。</p><p>操作不同状态的 chan 会引发三种行为:</p><ol><li>panic<ul><li>向已经关闭的通道写数据会导致 panic ;最佳实践是由写入者关闭通道,能最大程度地避免向已经关闭的通道写数据而导致的 panic;</li><li>重复关闭的通道会导致 panic;</li></ul></li><li>阻塞<ul><li>向未初始化的通道写数据或读数据都会导致当前 goroutine 的永久阻塞;</li><li>向缓冲区己满的通道写入数据会导致 goroutine 阻塞;</li><li>通道中没有数据,读取该通道会导致 goroutine 阻塞;</li></ul></li><li>非阻塞<ul><li>读取己经关闭的通道不会引发阻塞,而是立即返回通道元素类型的零值,可以使用 comrna , ok 语法判断通道是否己经关闭;</li><li>向有缓冲且没有满的通道读/写不会引发阻塞;</li></ul></li></ol><h2 id="1-4-WaitGroup"><a href="#1-4-WaitGroup" class="headerlink" title="1.4 WaitGroup"></a>1.4 WaitGroup</h2><p>goroutine 和 chan 一个用于并发,另一个用于通信。没有缓冲的通道具有同步的功能,除此之外, sync 包也提供了多个 goroutine 同步的机制,主要是通过 WaitGroup 实现的。</p><p>主要数据结构和操作如下:</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">type</span> WaitGroup <span class="token keyword">struct</span> <span class="token punctuation">{</span> <span class="token comment">// contains filtered or unexported fields</span><span class="token punctuation">}</span><span class="token comment">// 添加等待信号</span><span class="token keyword">func</span> <span class="token punctuation">(</span>wg <span class="token operator">*</span>WaitGroup<span class="token punctuation">)</span> <span class="token function">Add</span><span class="token punctuation">(</span>delta <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token comment">// 释放等待信号</span><span class="token keyword">func</span> <span class="token punctuation">(</span>wg <span class="token operator">*</span>WaitGroup<span class="token punctuation">)</span> <span class="token function">Done</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 等待</span><span class="token keyword">func</span> <span class="token punctuation">(</span>wg <span class="token operator">*</span>WaitGroup<span class="token punctuation">)</span> <span class="token function">Wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>WaitGroup 用来等待多个 goroutine 完成, main goroutine 调用 Add 设置需要等待 goroutine 的数目,每一个 goroutine 结束时调用 Done(), Wait() 被 main 用来等待所有的 goroutine 完成。</p><h2 id="1-5-select"><a href="#1-5-select" class="headerlink" title="1.5 select"></a>1.5 select</h2><p>select 是类 UNIX 系统提供的一个多路复用系统 API, Go 语言借用多路复用的概念,提供了 select 关键字,用于多路监昕多个通道。当监听的通道没有状态是可读或可写的, select 是阻塞的;只要监听的通道中有一个状态是可读或可写的,则 select 就不会阻塞,而是进入处理就绪通道的分支流程。如果监听的通道有多个可读或可写的状态, 则 select 随机选取一个处理。</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> ch <span class="token punctuation">:</span> <span class="token operator">=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span> <span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> <span class="token punctuation">{</span> <span class="token keyword">select</span> <span class="token punctuation">{</span> <span class="token comment">//0 或 1 的写入是随机的</span> <span class="token keyword">case</span> ch <span class="token operator"><</span> <span class="token operator">-</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token keyword">case</span> ch <span class="token operator"><-</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token punctuation">(</span>ch<span class="token punctuation">)</span> <span class="token keyword">for</span> i <span class="token punctuation">:</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">10</span><span class="token punctuation">;</span>i<span class="token operator">++</span> <span class="token punctuation">{</span> <span class="token function">println</span><span class="token punctuation">(</span><span class="token operator"><-</span>ch<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// 运行结果</span><span class="token number">0</span> <span class="token number">0</span> <span class="token number">1</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token number">1</span> <span class="token number">0</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">0</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="1-6-扇入(-Fan-in-)和扇出(-Fan-out"><a href="#1-6-扇入(-Fan-in-)和扇出(-Fan-out" class="headerlink" title="1.6 扇入( Fan in )和扇出( Fan out )"></a>1.6 扇入( Fan in )和扇出( Fan out )</h2><p>编程中经常遇到 “扇入和扇出” 两个概念,所谓的扇入是指将多路通道聚合到一条通道中处理,Go 语言最简单的扇入就是使用 sel ect 聚合多条通道服务;所谓的扇出是指将一条通道发散到多条通道中处理,在 Go 语言里面具体实现就是使用 go 关键字启动多个 goroutine 并发处理。</p><p>中国有句经典的哲学名句叫 “分久必合,合久必分” 软件的设计和开发也遵循同样的哲学思想,扇入就是合,扇出就是分。当生产者的速度很慢时,需要使用扇入技术聚合多个生产者满足消费者, 比如很耗时的加密/解密服务;当消费者的速度很慢时,需要使用扇出技术,比如Web 服务器并发请求处理。扇入和扇出是 Go 并发编程中常用的技术。</p><h3 id="1-6-1-扇入(Fan-In):"><a href="#1-6-1-扇入(Fan-In):" class="headerlink" title="1.6.1 扇入(Fan-In):"></a>1.6.1 扇入(Fan-In):</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">func</span> <span class="token function">fanIn</span><span class="token punctuation">(</span>input1<span class="token punctuation">,</span> input2 <span class="token operator"><-</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator"><-</span><span class="token keyword">chan</span> <span class="token builtin">string</span> <span class="token punctuation">{</span> c <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> <span class="token punctuation">{</span> <span class="token keyword">select</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> s <span class="token operator">:=</span> <span class="token operator"><-</span>input1<span class="token punctuation">:</span> c <span class="token operator"><-</span> s <span class="token keyword">case</span> s <span class="token operator">:=</span> <span class="token operator"><-</span>input2<span class="token punctuation">:</span> c <span class="token operator"><-</span> s <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">return</span> c<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>扇入指的是将多个输入 channel 合并到一个 channel 中,扇出是将一个输入 channel 分散给多个 worker 进行处理。</p><h3 id="1-6-2-扇出(Fan-Out):"><a href="#1-6-2-扇出(Fan-Out):" class="headerlink" title="1.6.2 扇出(Fan-Out):"></a>1.6.2 扇出(Fan-Out):</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">func</span> <span class="token function">fanOut</span><span class="token punctuation">(</span>input <span class="token operator"><-</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">,</span> workerCount <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator"><-</span><span class="token keyword">chan</span> <span class="token builtin">string</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> outputs <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator"><-</span><span class="token keyword">chan</span> <span class="token builtin">string</span> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> workerCount<span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> outputs <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>outputs<span class="token punctuation">,</span> <span class="token function">createWorker</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> outputs<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">createWorker</span><span class="token punctuation">(</span>input <span class="token operator"><-</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator"><-</span><span class="token keyword">chan</span> <span class="token builtin">string</span> <span class="token punctuation">{</span> c <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> n <span class="token operator">:=</span> <span class="token keyword">range</span> input <span class="token punctuation">{</span> c <span class="token operator"><-</span> <span class="token function">doWork</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">close</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">return</span> c<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">doWork</span><span class="token punctuation">(</span>n <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token builtin">string</span> <span class="token punctuation">{</span> <span class="token comment">//...执行一些操作...</span> <span class="token keyword">return</span> n<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>在以上扇出的例子中,<code>input</code>是输入channel,在<code>fanOut</code>函数中,我们根据<code>workerCount</code>创建相同数量的Worker来处理输入信息。每个Worker处理的任务是从输入channel读取信息,然后进行一些工作(在<code>doWork</code>函数中定义),然后将信息写入自己的输出channel中。Workers的输出channel会被添加到<code>outputs</code>切片中,并从<code>fanOut</code>函数返回。</p><h3 id="1-6-3-扇入扇出分别对应的应用场景"><a href="#1-6-3-扇入扇出分别对应的应用场景" class="headerlink" title="1.6.3 扇入扇出分别对应的应用场景"></a>1.6.3 扇入扇出分别对应的应用场景</h3><p>扇入和扇出的概念常用在处理并发和流处理系统中,它们各自有一些常见的应用场景:</p><p><strong>(1)扇入(Fan-In)</strong><br>扇入是将来自多个源的数据聚合到一个通道中,这种方式常用于多个并行或异步任务完成时集中处理结果,如:</p><ol><li>对来自多个源的日志或状态更新聚合到一个处理者,以实现统一的日志记录、分析或监控。</li><li>在分布式计算的上下文中,多个节点可能正在并行处理任务,并在完成时将结果发送回中央节点以进行聚合和处理。</li></ol><p><strong>(2)扇出(Fan-Out)</strong><br>扇出是将数据从一个源分发到多个接收者的过程,每个接收者都会得到完整的数据拷贝,扇出可以提高处理或任务的吞吐量。具体应用可能包括:</p><ol><li>在负载均衡的上下文中,扇出通常用作一种将任务分发到多个工作节点的手段以提高整体处理速度,每个节点处理部分工作负载。</li><li>在自然语言处理或图像处理等领域,可以使用扇出来并行训练或运行多个模型,然后比较各自的输出以确定最优解。</li><li>扇出模式还可以用于数据备份和冗余存储的场景。比如,我们可以将一个流量的数据同时发送到多个存储节点,以此达到数据的备份和冗余保障。</li></ol><h2 id="1-7-通知退出机制"><a href="#1-7-通知退出机制" class="headerlink" title="1.7 通知退出机制"></a>1.7 通知退出机制</h2><p>读取己经关闭的通道不会引起阻塞,也不会导致 panic ,而是立即返回该通道存储类型的零值。关闭 select 监听的某个通道能使 select 立即感知这种通知,然后进行相应的处理,这就是所谓的退出通知机制(close channel to broadcast )。下面通过一个随机数生成器的示例演示退出通知机制,下游的消费者不需要随机数时,显式地通知生产者停止生产。</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token comment">// GenerateintA 是一个随机数生成器</span><span class="token keyword">func</span> <span class="token function">GenerateintA</span><span class="token punctuation">(</span>done <span class="token keyword">chan</span> <span class="token keyword">struct</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">chan</span> <span class="token builtin">int</span> <span class="token punctuation">{</span>ch <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span><span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>Label<span class="token punctuation">:</span><span class="token keyword">for</span> <span class="token punctuation">{</span><span class="token keyword">select</span> <span class="token punctuation">{</span><span class="token keyword">case</span> ch <span class="token operator"><-</span> rand<span class="token punctuation">.</span><span class="token function">Int</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span><span class="token keyword">case</span> <span class="token operator"><-</span>done<span class="token punctuation">:</span><span class="token keyword">break</span> Label<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token function">close</span><span class="token punctuation">(</span>ch<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">return</span> ch<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>done <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token keyword">struct</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>ch <span class="token operator">:=</span> <span class="token function">GenerateintA</span><span class="token punctuation">(</span>done<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator"><-</span>ch<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator"><-</span>ch<span class="token punctuation">)</span><span class="token function">close</span><span class="token punctuation">(</span>done<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator"><-</span>ch<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator"><-</span>ch<span class="token punctuation">)</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"NumGoroutine="</span><span class="token punctuation">,</span> runtime<span class="token punctuation">.</span><span class="token function">NumGoroutine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 输出结果</span><span class="token number">146870834388028874</span><span class="token number">7216694335601338127</span><span class="token number">0</span><span class="token number">0</span>NumGoroutine<span class="token operator">=</span> <span class="token number">1</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="1-8-并发范式"><a href="#1-8-并发范式" class="headerlink" title="1.8 并发范式"></a>1.8 并发范式</h2><p>通过具体的程序示例来演示 Go 语言强大的并发处理能力,每个示例代表一个并发处理范式,这些范式具有典型的特征,在真实的程序中稍加改造就能使用。</p><h3 id="1-8-1-生成器"><a href="#1-8-1-生成器" class="headerlink" title="1.8.1 生成器"></a>1.8.1 生成器</h3><p>在应用系统编程中,常见的应用场景就是调用一个统一的全局的生成器服务, 用于生成全局事务号、订单号、序列号和随机数等。 Go 对这种场景的支持非常简单,下面以一个随机数生成器为例来说明。</p><ol><li>最简单的带缓冲的生成器。 例如:</li></ol><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token comment">// RandomNumber 是一个随机数生成器</span><span class="token keyword">func</span> <span class="token function">RandomNumber</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">chan</span> <span class="token builtin">int</span> <span class="token punctuation">{</span>ch <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token comment">// 启动一个 go routine 用于生成随机数,函数返回一个通道用于获取随机数</span><span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">for</span> <span class="token punctuation">{</span>ch <span class="token operator"><-</span> rand<span class="token punctuation">.</span><span class="token function">Int</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">return</span> ch<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>ch <span class="token operator">:=</span> <span class="token function">RandomNumber</span><span class="token punctuation">(</span><span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator"><-</span>ch<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator"><-</span>ch<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 输出结果</span><span class="token number">8442295699646266936</span><span class="token number">6343099628820528177</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><ol start="2"><li>多个 goroutine 增强型生成器。 例如:</li></ol><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token comment">// RandomNumber1 是一个随机数生成器</span><span class="token keyword">func</span> <span class="token function">RandomNumber1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">chan</span> <span class="token builtin">int</span> <span class="token punctuation">{</span>ch <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span><span class="token comment">// 启动一个 go routine 用于生成随机数,函数返回一个通道用于获取随机数</span><span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">for</span> <span class="token punctuation">{</span>ch <span class="token operator"><-</span> rand<span class="token punctuation">.</span><span class="token function">Int</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">return</span> ch<span class="token punctuation">}</span><span class="token comment">// RandomNumber2 是一个随机数生成器</span><span class="token keyword">func</span> <span class="token function">RandomNumber2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">chan</span> <span class="token builtin">int</span> <span class="token punctuation">{</span>ch <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span><span class="token comment">// 启动一个 go routine 用于生成随机数,函数返回一个通道用于获取随机数</span><span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">for</span> <span class="token punctuation">{</span>ch <span class="token operator"><-</span> rand<span class="token punctuation">.</span><span class="token function">Int</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">return</span> ch<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">GenerateInt</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">chan</span> <span class="token builtin">int</span> <span class="token punctuation">{</span>ch <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span><span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">for</span> <span class="token punctuation">{</span><span class="token keyword">select</span> <span class="token punctuation">{</span><span class="token keyword">case</span> ch <span class="token operator"><-</span> <span class="token operator"><-</span><span class="token function">RandomNumber1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span><span class="token keyword">case</span> ch <span class="token operator"><-</span> <span class="token operator"><-</span><span class="token function">RandomNumber2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">return</span> ch<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>ch <span class="token operator">:=</span> <span class="token function">GenerateInt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">100</span><span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator"><-</span>ch<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// 输出结果</span><span class="token number">4732711589376798349</span><span class="token number">5980361011433472918</span><span class="token number">8507484322095864034</span><span class="token operator">...</span><span class="token operator">...</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="1-8-2-管道"><a href="#1-8-2-管道" class="headerlink" title="1.8.2 管道"></a>1.8.2 管道</h3><p>通道可以分为两个方向,一个是读,另一个是写,假如一个函数的输入参数和输出参数都是相同的 chan 类型, 则该函数可以调用自己,最终形成一个调用链。当然多个具有相同参数类型的函数也能组成一个调用链,这很像 UNIX 系统的管道,是一个有类型的管道。</p><p>下面通过具体的示例演示 Go 程序这种链式处理能力:</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span><span class="token punctuation">)</span><span class="token comment">// chain 函数的输入参数和输出参数类型相同,都是 chan int 类型</span><span class="token comment">// chain 函数的功能是将 chan 内的数据统一加1</span><span class="token keyword">func</span> <span class="token function">chain</span><span class="token punctuation">(</span>in <span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token keyword">chan</span> <span class="token builtin">int</span> <span class="token punctuation">{</span> out <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">for</span> v <span class="token operator">:=</span> <span class="token keyword">range</span> in<span class="token punctuation">{</span> out <span class="token operator"><-</span> <span class="token number">1</span> <span class="token operator">+</span> v <span class="token punctuation">}</span> <span class="token function">close</span><span class="token punctuation">(</span>out<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">return</span> out<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> in <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">10</span><span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> in <span class="token operator"><-</span> i <span class="token punctuation">}</span> <span class="token function">close</span><span class="token punctuation">(</span>in<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 连续调用 3 次 chan,相当于把 in 中的每个元素都加 3</span> out <span class="token operator">:=</span> <span class="token function">chain</span><span class="token punctuation">(</span><span class="token function">chain</span><span class="token punctuation">(</span><span class="token function">chain</span><span class="token punctuation">(</span>in<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">for</span> v <span class="token operator">:=</span> <span class="token keyword">range</span> out <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>v<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="1-8-3-每个请求一个-goroutine"><a href="#1-8-3-每个请求一个-goroutine" class="headerlink" title="1.8.3 每个请求一个 goroutine"></a>1.8.3 每个请求一个 goroutine</h3><p>下面以计算 100 个自然数的和来举例,将计算任务拆分为多个 task,每个 task 启动一个 goroutine 进行处理,程序示例代码如下:</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"sync"</span><span class="token punctuation">)</span><span class="token comment">// 工作任务</span><span class="token keyword">type</span> task <span class="token keyword">struct</span> <span class="token punctuation">{</span>begin <span class="token builtin">int</span>end <span class="token builtin">int</span>result <span class="token keyword">chan</span><span class="token operator"><-</span> <span class="token builtin">int</span><span class="token punctuation">}</span><span class="token comment">// 任务执行:计算 begin 到 end 的和</span><span class="token comment">// 执行结果写入到结果 chan result 中</span><span class="token keyword">func</span> <span class="token punctuation">(</span>t <span class="token operator">*</span>task<span class="token punctuation">)</span> <span class="token function">do</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>sum <span class="token operator">:=</span> <span class="token number">0</span><span class="token keyword">for</span> i <span class="token operator">:=</span> t<span class="token punctuation">.</span>begin<span class="token punctuation">;</span> i <span class="token operator"><=</span> t<span class="token punctuation">.</span>end<span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span>sum <span class="token operator">+=</span> i<span class="token punctuation">}</span>t<span class="token punctuation">.</span>result <span class="token operator"><-</span> sum<span class="token punctuation">}</span><span class="token comment">// 构建 task 并写入到 task 通道</span><span class="token keyword">func</span> <span class="token function">InitTask</span><span class="token punctuation">(</span>taskchan <span class="token keyword">chan</span><span class="token operator"><-</span> task<span class="token punctuation">,</span> r <span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">,</span> p <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>qu <span class="token operator">:=</span> p <span class="token operator">/</span> <span class="token number">10</span>mod <span class="token operator">:=</span> p <span class="token operator">%</span> <span class="token number">10</span>high <span class="token operator">:=</span> qu <span class="token operator">*</span> <span class="token number">10</span><span class="token keyword">for</span> j <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator"><</span> qu<span class="token punctuation">;</span> j<span class="token operator">++</span> <span class="token punctuation">{</span>b <span class="token operator">:=</span> <span class="token number">10</span><span class="token operator">*</span>j <span class="token operator">+</span> <span class="token number">1</span>e <span class="token operator">:=</span> <span class="token number">10</span> <span class="token operator">*</span> <span class="token punctuation">(</span>j <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span>tsk <span class="token operator">:=</span> task<span class="token punctuation">{</span>begin<span class="token punctuation">:</span> b<span class="token punctuation">,</span>end<span class="token punctuation">:</span> e<span class="token punctuation">,</span>result<span class="token punctuation">:</span> r<span class="token punctuation">,</span><span class="token punctuation">}</span>taskchan <span class="token operator"><-</span> tsk<span class="token punctuation">}</span><span class="token keyword">if</span> mod <span class="token operator">!=</span> <span class="token number">0</span> <span class="token punctuation">{</span>tsk <span class="token operator">:=</span> task<span class="token punctuation">{</span>begin<span class="token punctuation">:</span> high <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span>end<span class="token punctuation">:</span> p<span class="token punctuation">,</span>result<span class="token punctuation">:</span> r<span class="token punctuation">,</span><span class="token punctuation">}</span>taskchan <span class="token operator"><-</span> tsk<span class="token punctuation">}</span><span class="token function">close</span><span class="token punctuation">(</span>taskchan<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 读取 task chan ,每个 task 一个 worker goroutine 处理</span><span class="token comment">// 并等待每个 task 运行完,关闭结果通道</span><span class="token keyword">func</span> <span class="token function">DistributeTask</span><span class="token punctuation">(</span>taskchan <span class="token operator"><-</span><span class="token keyword">chan</span> task<span class="token punctuation">,</span> wait <span class="token operator">*</span>sync<span class="token punctuation">.</span>WaitGroup<span class="token punctuation">,</span> result <span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">for</span> v <span class="token operator">:=</span> <span class="token keyword">range</span> taskchan <span class="token punctuation">{</span>wait<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token keyword">go</span> <span class="token function">ProcessTask</span><span class="token punctuation">(</span>v<span class="token punctuation">,</span> wait<span class="token punctuation">)</span><span class="token punctuation">}</span>wait<span class="token punctuation">.</span><span class="token function">Wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token function">close</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 工作 goroutine 处理具体工作,并将处理结构发送到结果通道</span><span class="token keyword">func</span> <span class="token function">ProcessTask</span><span class="token punctuation">(</span>t task<span class="token punctuation">,</span> wait <span class="token operator">*</span>sync<span class="token punctuation">.</span>WaitGroup<span class="token punctuation">)</span> <span class="token punctuation">{</span>t<span class="token punctuation">.</span><span class="token function">do</span><span class="token punctuation">(</span><span class="token punctuation">)</span>wait<span class="token punctuation">.</span><span class="token function">Done</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 读取结果通道,汇总结果</span><span class="token keyword">func</span> <span class="token function">ProcessResult</span><span class="token punctuation">(</span>resultchan <span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token builtin">int</span> <span class="token punctuation">{</span>sum <span class="token operator">:=</span> <span class="token number">0</span><span class="token keyword">for</span> r <span class="token operator">:=</span> <span class="token keyword">range</span> resultchan <span class="token punctuation">{</span>sum <span class="token operator">+=</span> r<span class="token punctuation">}</span><span class="token keyword">return</span> sum<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 创建任务通道</span>taskchan <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> task<span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token comment">// 创建结果通道</span>resultchan <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token comment">// wait 用于同步等待任务的执行</span>wait <span class="token operator">:=</span> <span class="token operator">&</span>sync<span class="token punctuation">.</span>WaitGroup<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token comment">// 初始化 task 的 goroutine,计算 100 个自然数之和</span><span class="token keyword">go</span> <span class="token function">InitTask</span><span class="token punctuation">(</span>taskchan<span class="token punctuation">,</span> resultchan<span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token comment">//每个 task 启动一个 goroutine 处理,</span><span class="token keyword">go</span> <span class="token function">DistributeTask</span><span class="token punctuation">(</span>taskchan<span class="token punctuation">,</span> wait<span class="token punctuation">,</span> resultchan<span class="token punctuation">)</span><span class="token comment">// 通过结果通道获取结果并汇总</span>sum <span class="token operator">:=</span> <span class="token function">ProcessResult</span><span class="token punctuation">(</span>resultchan<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"sum="</span><span class="token punctuation">,</span> sum<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 结果</span>sum<span class="token operator">=</span> <span class="token number">5050</span> <span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>程序的逻辑分析:<br>(1)InitTask 函数构建 task 并发送到 task 通道中;<br>(2)分发任务函数 DistributeTask 为每个 task 启动一个 goroutine 处理任务, 等待其处理完成, 然后关闭结果通道;<br>(3)ProcessResult 函数读取并统计所有的结果。这几个函数分别在不同的 goroutine 中运行, 它们通过通道和sync.WaitGroup 进行通信和同步;</p><h3 id="1-8-4-固定-worker-工作池"><a href="#1-8-4-固定-worker-工作池" class="headerlink" title="1.8.4 固定 worker 工作池"></a>1.8.4 固定 worker 工作池</h3><p>服务器编程中使用最多的就是通过线程池来提升服务的井发处理能力。在 Go 语言编程中,<br>一样可以轻松地构建固定数目的 goroutines 作为工作线程池。下面还是以计算多个整数的和为例来说明这种并发范式。程序中除了主要的 main goroutine ,还开启了如下几类 goroutine:<br>(1)初始化任务的 goroutme;<br>(2)分发任务的 goroutine;<br>(3)等待所有 worker 结束通知,然后关闭结果通道的 goroutine;<br>main 函数负责拉起上述 goroutine ,并从结果通道获取最终的结果;<br>程序采用三个通道,分别是:<br>(1)传递 task 任务的通道;<br>(2)传递 task 结果的通道;<br>(3)接收 worker 处理完任务后所发送通知的通道;<br>相关的代码如下:</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token punctuation">)</span><span class="token comment">// 工作池的 goroutine 数目</span><span class="token keyword">const</span> <span class="token punctuation">(</span>NUMBER <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token comment">// 工作任务</span><span class="token keyword">type</span> task <span class="token keyword">struct</span> <span class="token punctuation">{</span>begin <span class="token builtin">int</span>end <span class="token builtin">int</span>result <span class="token keyword">chan</span><span class="token operator"><-</span> <span class="token builtin">int</span><span class="token punctuation">}</span><span class="token comment">// 任务处理:计算 begin 到 end 的和</span><span class="token comment">// 执行结果写入到结果 chan result 中</span><span class="token keyword">func</span> <span class="token punctuation">(</span>t <span class="token operator">*</span>task<span class="token punctuation">)</span> <span class="token function">do</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>sum <span class="token operator">:=</span> <span class="token number">0</span><span class="token keyword">for</span> i <span class="token operator">:=</span> t<span class="token punctuation">.</span>begin<span class="token punctuation">;</span> i <span class="token operator"><=</span> t<span class="token punctuation">.</span>end<span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span>sum <span class="token operator">+=</span> i<span class="token punctuation">}</span>t<span class="token punctuation">.</span>result <span class="token operator"><-</span> sum<span class="token punctuation">}</span><span class="token comment">// 初始化待处理 task chan</span><span class="token keyword">func</span> <span class="token function">InitTask</span><span class="token punctuation">(</span>taskchan <span class="token keyword">chan</span><span class="token operator"><-</span> task<span class="token punctuation">,</span> r <span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">,</span> p <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>qu <span class="token operator">:=</span> p <span class="token operator">/</span> <span class="token number">10</span>mod <span class="token operator">:=</span> p <span class="token operator">%</span> <span class="token number">10</span>high <span class="token operator">:=</span> qu <span class="token operator">*</span> <span class="token number">10</span><span class="token keyword">for</span> j <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator"><</span> qu<span class="token punctuation">;</span> j<span class="token operator">++</span> <span class="token punctuation">{</span>b <span class="token operator">:=</span> <span class="token number">10</span><span class="token operator">*</span>j <span class="token operator">+</span> <span class="token number">1</span>e <span class="token operator">:=</span> <span class="token number">10</span> <span class="token operator">*</span> <span class="token punctuation">(</span>j <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span>tsk <span class="token operator">:=</span> task<span class="token punctuation">{</span>begin<span class="token punctuation">:</span> b<span class="token punctuation">,</span>end<span class="token punctuation">:</span> e<span class="token punctuation">,</span>result<span class="token punctuation">:</span> r<span class="token punctuation">,</span><span class="token punctuation">}</span>taskchan <span class="token operator"><-</span> tsk<span class="token punctuation">}</span><span class="token keyword">if</span> mod <span class="token operator">!=</span> <span class="token number">0</span> <span class="token punctuation">{</span>tsk <span class="token operator">:=</span> task<span class="token punctuation">{</span>begin<span class="token punctuation">:</span> high <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span>end<span class="token punctuation">:</span> p<span class="token punctuation">,</span>result<span class="token punctuation">:</span> r<span class="token punctuation">,</span><span class="token punctuation">}</span>taskchan <span class="token operator"><-</span> tsk<span class="token punctuation">}</span><span class="token function">close</span><span class="token punctuation">(</span>taskchan<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 读取 task chan 分发到 worker goroutine 处理,workers 的总的数量是 workers</span><span class="token keyword">func</span> <span class="token function">DistributeTask</span><span class="token punctuation">(</span>taskchan <span class="token operator"><-</span><span class="token keyword">chan</span> task<span class="token punctuation">,</span> workers <span class="token builtin">int</span><span class="token punctuation">,</span> done <span class="token keyword">chan</span> <span class="token keyword">struct</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> workers<span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span><span class="token keyword">go</span> <span class="token function">ProcessTask</span><span class="token punctuation">(</span>taskchan<span class="token punctuation">,</span> done<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// 工作 goroutine 处理具体工作,并将处理结构发送到结果 chan</span><span class="token keyword">func</span> <span class="token function">ProcessTask</span><span class="token punctuation">(</span>taskchan <span class="token operator"><-</span><span class="token keyword">chan</span> task<span class="token punctuation">,</span> done <span class="token keyword">chan</span> <span class="token keyword">struct</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">for</span> t <span class="token operator">:=</span> <span class="token keyword">range</span> taskchan <span class="token punctuation">{</span>t<span class="token punctuation">.</span><span class="token function">do</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span>done <span class="token operator"><-</span> <span class="token keyword">struct</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// 通过 done channel 来同步等待所有工作 goroutine 的结束,然后关闭结果 chan</span><span class="token keyword">func</span> <span class="token function">CloseResult</span><span class="token punctuation">(</span>done <span class="token keyword">chan</span> <span class="token keyword">struct</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> resultchan <span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">,</span> workers <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> workers<span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span><span class="token operator"><-</span>done<span class="token punctuation">}</span><span class="token function">close</span><span class="token punctuation">(</span>done<span class="token punctuation">)</span><span class="token function">close</span><span class="token punctuation">(</span>resultchan<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 读取结果通道,汇总结果</span><span class="token keyword">func</span> <span class="token function">ProcessResult</span><span class="token punctuation">(</span>resultchan <span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token builtin">int</span> <span class="token punctuation">{</span>sum <span class="token operator">:=</span> <span class="token number">0</span><span class="token keyword">for</span> r <span class="token operator">:=</span> <span class="token keyword">range</span> resultchan <span class="token punctuation">{</span>sum <span class="token operator">+=</span> r<span class="token punctuation">}</span><span class="token keyword">return</span> sum<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>workers <span class="token operator">:=</span> NUMBER<span class="token comment">// 工作通道</span>taskchan <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> task<span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token comment">// 结果通道</span>resultchan <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token comment">// worker 信号通道</span>done <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token keyword">struct</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token comment">// 初始化 task 的 goroutine,计算 1000 个自然数之和</span><span class="token keyword">go</span> <span class="token function">InitTask</span><span class="token punctuation">(</span>taskchan<span class="token punctuation">,</span> resultchan<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token comment">// 分发任务在 NUMBER 个 goroutine 池</span><span class="token function">DistributeTask</span><span class="token punctuation">(</span>taskchan<span class="token punctuation">,</span> workers<span class="token punctuation">,</span> done<span class="token punctuation">)</span><span class="token comment">// 获取各个 goroutine 处理完任务的通知,并关闭结果通道</span><span class="token keyword">go</span> <span class="token function">CloseResult</span><span class="token punctuation">(</span>done<span class="token punctuation">,</span> resultchan<span class="token punctuation">,</span> workers<span class="token punctuation">)</span><span class="token comment">// 通过结果通道处理结果</span>sum <span class="token operator">:=</span> <span class="token function">ProcessResult</span><span class="token punctuation">(</span>resultchan<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"sum="</span><span class="token punctuation">,</span> sum<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 结果</span>sum<span class="token operator">=</span> <span class="token number">5050</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>程序的逻辑分析:<br>(1)构建 task 并发送到 task 通道中;<br>(2)分别启动 n 个工作线程,不停地从 task 通道中获取任务,然后将结果写入结果通道。如果任务通道被关闭,则负责向收敛结果的 goroutine 发送通知,告诉其当前 worker 已经完成工作;<br>(3)收敛结果的 goroutine 接收到所有 task 己经处理完毕的信号后,主动关闭结果通道;<br>(4)main 中的函数 ProcessResult 读取并统计所有的结果;</p><h3 id="1-8-5-future-模式"><a href="#1-8-5-future-模式" class="headerlink" title="1.8.5 future 模式"></a>1.8.5 future 模式</h3><p>编程中经常遇到在一个流程中需要调用多个子调用的情况,这些子调用相互之间没有依赖,如果串行地调用,则耗时会很长,此时可以使用 Go 并发编程中的 future 模式。<br>future 模式的基本工作原理:<br>(1)使用 chan 作为函数参数;<br>(2)启动 goroutine 调用函数;<br>(3)通过 chan 传入参数;<br>(4)做其他可以并行处理的事情;<br>(5)通过 chan 异步获取结果;<br>下面通过一段抽象的代码来学习该模式:</p><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"time"</span><span class="token punctuation">)</span><span class="token comment">// 一个查询结构体</span><span class="token comment">// 这里的 sql 和 result 是一个简单的抽象,具体的应用,可能是更复杂的数据类型</span><span class="token keyword">type</span> query <span class="token keyword">struct</span> <span class="token punctuation">{</span><span class="token comment">// 参数 Channel</span>sql <span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token comment">// 结果 Channel</span>result <span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">}</span><span class="token comment">// 执行 Query</span><span class="token keyword">func</span> <span class="token function">execQuery</span><span class="token punctuation">(</span>q query<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 启动协程</span><span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 获取输入</span>sql <span class="token operator">:=</span> <span class="token operator"><-</span>q<span class="token punctuation">.</span>sql<span class="token comment">// 访问数据库</span><span class="token comment">// 输出结果通道</span>q<span class="token punctuation">.</span>result <span class="token operator"><-</span> <span class="token string">"result from "</span> <span class="token operator">+</span> sql<span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 初始化 Query</span>q <span class="token operator">:=</span> query<span class="token punctuation">{</span><span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 执行 Query,注意执行的时候无需准备参数</span><span class="token keyword">go</span> <span class="token function">execQuery</span><span class="token punctuation">(</span>q<span class="token punctuation">)</span><span class="token comment">//准备参数</span>q<span class="token punctuation">.</span>sql <span class="token operator"><-</span> <span class="token string">"select * from table;"</span><span class="token comment">// do otherthings</span>time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">*</span> time<span class="token punctuation">.</span>Second<span class="token punctuation">)</span><span class="token comment">//获取结果</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator"><-</span>q<span class="token punctuation">.</span>result<span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><p>future 最大的好处是将函数的同步调用转换为异步调用, 适用于一个交易需要多个子调用且这些子调用没有依赖的场景。 实际情况可能比上面示例复杂得多,要考虑错误和异常的处理。</p>]]></content>
<summary type="html"><h1 id="1-并发"><a href="#1-并发" class="headerlink" title="1. 并发"></a>1. 并发</h1><h2 id="1-1-并发和并行的区别"><a href="#1-1-并发和并行的区别" class="headerli</summary>
<category term="Go进阶" scheme="http://coderedeng.github.io/categories/Go%E8%BF%9B%E9%98%B6/"/>
<category term="Go进阶" scheme="http://coderedeng.github.io/tags/Go%E8%BF%9B%E9%98%B6/"/>
</entry>
<entry>
<title>regexp2</title>
<link href="http://coderedeng.github.io/2022/06/23/Go%E5%B8%B8%E7%94%A8%E5%BA%93%E4%BB%8B%E7%BB%8D%20-%20regexp2/"/>
<id>http://coderedeng.github.io/2022/06/23/Go%E5%B8%B8%E7%94%A8%E5%BA%93%E4%BB%8B%E7%BB%8D%20-%20regexp2/</id>
<published>2022-06-23T14:02:41.000Z</published>
<updated>2026-06-07T01:21:54.895Z</updated>
<content type="html"><![CDATA[<h1 id="21-regexp2"><a href="#21-regexp2" class="headerlink" title="21.regexp2"></a>21.regexp2</h1><h2 id="01-regexp2"><a href="#01-regexp2" class="headerlink" title="01.regexp2"></a>01.regexp2</h2><ul><li>Regexp2:<a href="https://blog.csdn.net/dianxin113/article/details/118769094">https://blog.csdn.net/dianxin113/article/details/118769094</a></li><li>GitHub:<a href="https://github.com/dlclark/regexp2">https://github.com/dlclark/regexp2</a></li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"github.com/dlclark/regexp2"</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">Regexp2GroupMatch</span><span class="token punctuation">(</span>m <span class="token operator">*</span>regexp2<span class="token punctuation">.</span>Match<span class="token punctuation">,</span> re <span class="token operator">*</span>regexp2<span class="token punctuation">.</span>Regexp<span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span> <span class="token punctuation">{</span><span class="token keyword">var</span> matches <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token keyword">for</span> m <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span><span class="token keyword">var</span> ret <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span>gps <span class="token operator">:=</span> m<span class="token punctuation">.</span><span class="token function">Groups</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">for</span> index<span class="token punctuation">,</span> g <span class="token operator">:=</span> <span class="token keyword">range</span> gps <span class="token punctuation">{</span><span class="token keyword">if</span> index <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span><span class="token keyword">continue</span><span class="token punctuation">}</span>ret <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>ret<span class="token punctuation">,</span> g<span class="token punctuation">.</span>Captures<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>matches <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>matches<span class="token punctuation">,</span> ret<span class="token punctuation">)</span>m<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">=</span> re<span class="token punctuation">.</span><span class="token function">FindNextMatch</span><span class="token punctuation">(</span>m<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">return</span> matches<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">CompileRegexp</span><span class="token punctuation">(</span>regex <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token operator">*</span>regexp2<span class="token punctuation">.</span>Regexp<span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>msgRegexp<span class="token punctuation">,</span> e <span class="token operator">:=</span> regexp2<span class="token punctuation">.</span><span class="token function">Compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token keyword">if</span> e <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">return</span> msgRegexp<span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>str <span class="token operator">:=</span> <span class="token string">"2022-8-12 2023-8-11"</span>expr <span class="token operator">:=</span> <span class="token string">"(\\d{4})-(\\d{1,2})-(\\d{1,2})"</span> <span class="token comment">// [[2022 8 12]]</span>reg<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> <span class="token function">CompileRegexp</span><span class="token punctuation">(</span>expr<span class="token punctuation">)</span>m<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> reg<span class="token punctuation">.</span><span class="token function">FindStringMatch</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span>ret <span class="token operator">:=</span> <span class="token function">Regexp2GroupMatch</span><span class="token punctuation">(</span>m<span class="token punctuation">,</span> reg<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>ret<span class="token punctuation">)</span> <span class="token comment">// [[2022 8 12] [2023 8 11]]</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure>]]></content>
<summary type="html"><h1 id="21-regexp2"><a href="#21-regexp2" class="headerlink" title="21.regexp2"></a>21.regexp2</h1><h2 id="01-regexp2"><a href="#01-regexp2"</summary>
<category term="Go常用库" scheme="http://coderedeng.github.io/categories/Go%E5%B8%B8%E7%94%A8%E5%BA%93/"/>
<category term="Go常用库" scheme="http://coderedeng.github.io/tags/Go%E5%B8%B8%E7%94%A8%E5%BA%93/"/>
</entry>
<entry>
<title>machinery</title>
<link href="http://coderedeng.github.io/2022/06/22/Go%E5%B8%B8%E7%94%A8%E5%BA%93%E4%BB%8B%E7%BB%8D%20-%20machinery/"/>
<id>http://coderedeng.github.io/2022/06/22/Go%E5%B8%B8%E7%94%A8%E5%BA%93%E4%BB%8B%E7%BB%8D%20-%20machinery/</id>
<published>2022-06-22T14:52:21.000Z</published>
<updated>2026-06-07T01:21:54.895Z</updated>
<content type="html"><![CDATA[<h1 id="20-machinery"><a href="#20-machinery" class="headerlink" title="20.machinery"></a>20.machinery</h1><h2 id="01-异步框架machinery"><a href="#01-异步框架machinery" class="headerlink" title="01.异步框架machinery"></a>01.异步框架machinery</h2><ul><li><a href="https://github.com/RichardKnop/machinery">github地址(opens new window)</a></li></ul><h3 id="1-1-machinery介绍"><a href="#1-1-machinery介绍" class="headerlink" title="1.1 machinery介绍"></a>1.1 machinery介绍</h3><ul><li>go machinery框架类似python中常用celery框架,主要用于 异步任务和定时任务,有一下特性<ul><li>任务重试机制</li><li>延迟任务支持</li><li>任务回调机制</li><li>任务结果记录</li><li>支持Workflow模式:Chain,Group,Chord</li><li>多Brokers支持:Redis, AMQP, <a href="https://link.segmentfault.com/?enc=DHe3inPV2HBq6uxnZ2CEOg==.XhC+OAXOeJgqueAZ3HrM4nnCWizYNVCgbJcSKS7+sPE=">AWS SQS(opens new window)</a></li><li>多Backends支持:Redis, Memcache, AMQP, <a href="https://link.segmentfault.com/?enc=s1hIwqlq+qzLK6uutFwrfg==.LOQSm2d600WNtAuHuxnSX++/1hm1iNUspqC1IcqZPCrXnAQ23jRJTDMUunMDFawu2mQXughrPBtdSeR7f1l45w==">MongoDB(opens new window)</a></li></ul></li></ul><h3 id="1-2-架构"><a href="#1-2-架构" class="headerlink" title="1.2 架构"></a>1.2 架构</h3><ul><li>任务队列,简而言之就是一个放大的生产者消费者模型</li><li>用户请求会生成任务,队列的处理器程序充当消费者不断的消费任务。</li><li>基于这种框架设计思想,我们来看下machinery的简单设计结构图例<ul><li>Sender:业务推送模块,生成具体任务,可根据业务逻辑中,按交互进行拆分;</li><li>Broker:存储具体序列化后的任务,machinery中目前支持到Redis, AMQP,和SQS;</li><li>Worker:工作进程,负责消费者功能,处理具体的任务;</li><li>Backend:后端存储,用于存储任务执行状态的数据;</li></ul></li></ul><p><img src="/img/image-20220206111846252.6cdeba77.png"></p><h2 id="02-machinery使用"><a href="#02-machinery使用" class="headerlink" title="02.machinery使用"></a>02.machinery使用</h2><h3 id="2-1-异步和定时任务"><a href="#2-1-异步和定时任务" class="headerlink" title="2.1 异步和定时任务"></a>2.1 异步和定时任务</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span>redisbackend <span class="token string">"github.com/RichardKnop/machinery/v2/backends/redis"</span>redisbroker <span class="token string">"github.com/RichardKnop/machinery/v2/brokers/redis"</span>eagerlock <span class="token string">"github.com/RichardKnop/machinery/v2/locks/eager"</span><span class="token string">"github.com/RichardKnop/machinery/v2"</span><span class="token string">"github.com/RichardKnop/machinery/v2/config"</span><span class="token string">"github.com/RichardKnop/machinery/v2/tasks"</span><span class="token string">"os"</span><span class="token string">"time"</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>os<span class="token punctuation">.</span>Args<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">2</span> <span class="token operator">&&</span> os<span class="token punctuation">.</span>Args<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">"worker"</span> <span class="token punctuation">{</span> <span class="token comment">// 启动worker</span><span class="token keyword">if</span> err <span class="token operator">:=</span> <span class="token function">worker</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span><span class="token function">panic</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token function">TestPeriodicTask</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 触发一个定时任务(定时任务由客户端控制,客户端退出定时就会结束)</span><span class="token function">TestAdd</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 触发一个异步任务</span>time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Second <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">/* 触发执行Add异步任务 */</span><span class="token keyword">func</span> <span class="token function">TestAdd</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>server<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> <span class="token function">startServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">// 调用异步任务 Add 函数,执行 1+4=5这个逻辑</span>signature <span class="token operator">:=</span> <span class="token operator">&</span>tasks<span class="token punctuation">.</span>Signature<span class="token punctuation">{</span>Name<span class="token punctuation">:</span> <span class="token string">"add"</span><span class="token punctuation">,</span>Args<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>tasks<span class="token punctuation">.</span>Arg<span class="token punctuation">{</span><span class="token punctuation">{</span>Type<span class="token punctuation">:</span> <span class="token string">"int64"</span><span class="token punctuation">,</span>Value<span class="token punctuation">:</span> <span class="token number">4</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">{</span>Type<span class="token punctuation">:</span> <span class="token string">"int64"</span><span class="token punctuation">,</span>Value<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span>asyncResult<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> server<span class="token punctuation">.</span><span class="token function">SendTask</span><span class="token punctuation">(</span>signature<span class="token punctuation">)</span> <span class="token comment">// 任务可以通过将Signature的实例传递给Server实例来调用</span>results<span class="token punctuation">,</span><span class="token boolean">_</span> <span class="token operator">:=</span> asyncResult<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">5</span><span class="token punctuation">)</span> <span class="token comment">// 您还可以执行同步阻塞调用来等待任务结果</span><span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> result <span class="token operator">:=</span> <span class="token keyword">range</span> results <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token function">Interface</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">/* 触发执行periodicTask异步任务 */</span><span class="token keyword">func</span> <span class="token function">TestPeriodicTask</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>server<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> <span class="token function">startServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>signature <span class="token operator">:=</span> <span class="token operator">&</span>tasks<span class="token punctuation">.</span>Signature<span class="token punctuation">{</span>Name<span class="token punctuation">:</span> <span class="token string">"periodicTask"</span><span class="token punctuation">,</span>Args<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>tasks<span class="token punctuation">.</span>Arg<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token comment">// 每分钟执行一次periodicTask函数,验证发现不支持秒级别定时任务</span>err <span class="token operator">:=</span> server<span class="token punctuation">.</span><span class="token function">RegisterPeriodicTask</span><span class="token punctuation">(</span><span class="token string">"*/1 * * * ?"</span><span class="token punctuation">,</span> <span class="token string">"periodic-task"</span><span class="token punctuation">,</span> signature<span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">}</span>asyncResult<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> server<span class="token punctuation">.</span><span class="token function">SendTask</span><span class="token punctuation">(</span>signature<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>asyncResult<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 第一:配置Server并注册任务</span><span class="token keyword">func</span> <span class="token function">startServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token operator">*</span>machinery<span class="token punctuation">.</span>Server<span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>cnf <span class="token operator">:=</span> <span class="token operator">&</span>config<span class="token punctuation">.</span>Config<span class="token punctuation">{</span>DefaultQueue<span class="token punctuation">:</span> <span class="token string">"machinery_tasks"</span><span class="token punctuation">,</span>ResultsExpireIn<span class="token punctuation">:</span> <span class="token number">3600</span><span class="token punctuation">,</span>Redis<span class="token punctuation">:</span> <span class="token operator">&</span>config<span class="token punctuation">.</span>RedisConfig<span class="token punctuation">{</span>MaxIdle<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span>IdleTimeout<span class="token punctuation">:</span> <span class="token number">240</span><span class="token punctuation">,</span>ReadTimeout<span class="token punctuation">:</span> <span class="token number">15</span><span class="token punctuation">,</span>WriteTimeout<span class="token punctuation">:</span> <span class="token number">15</span><span class="token punctuation">,</span>ConnectTimeout<span class="token punctuation">:</span> <span class="token number">15</span><span class="token punctuation">,</span>NormalTasksPollPeriod<span class="token punctuation">:</span> <span class="token number">1000</span><span class="token punctuation">,</span>DelayedTasksPollPeriod<span class="token punctuation">:</span> <span class="token number">500</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token comment">// 创建服务器实例</span>broker <span class="token operator">:=</span> redisbroker<span class="token punctuation">.</span><span class="token function">NewGR</span><span class="token punctuation">(</span>cnf<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token string">"localhost:6379"</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>backend <span class="token operator">:=</span> redisbackend<span class="token punctuation">.</span><span class="token function">NewGR</span><span class="token punctuation">(</span>cnf<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token string">"localhost:6379"</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>lock <span class="token operator">:=</span> eagerlock<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span>server <span class="token operator">:=</span> machinery<span class="token punctuation">.</span><span class="token function">NewServer</span><span class="token punctuation">(</span>cnf<span class="token punctuation">,</span> broker<span class="token punctuation">,</span> backend<span class="token punctuation">,</span> lock<span class="token punctuation">)</span><span class="token comment">// 注册异步任务</span>tasksMap <span class="token operator">:=</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span><span class="token keyword">interface</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">{</span><span class="token string">"add"</span><span class="token punctuation">:</span> Add<span class="token punctuation">,</span><span class="token string">"periodicTask"</span><span class="token punctuation">:</span> PeriodicTask<span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token keyword">return</span> server<span class="token punctuation">,</span> server<span class="token punctuation">.</span><span class="token function">RegisterTasks</span><span class="token punctuation">(</span>tasksMap<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 第二步:启动Worker</span><span class="token keyword">func</span> <span class="token function">worker</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span><span class="token comment">//消费者的标记</span>consumerTag <span class="token operator">:=</span> <span class="token string">"machinery_worker"</span>server<span class="token punctuation">,</span> err <span class="token operator">:=</span> <span class="token function">startServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span><span class="token keyword">return</span> err<span class="token punctuation">}</span><span class="token comment">//第二个参数并发数, 0表示不限制</span>worker <span class="token operator">:=</span> server<span class="token punctuation">.</span><span class="token function">NewWorker</span><span class="token punctuation">(</span>consumerTag<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token comment">//钩子函数</span>errorhandler <span class="token operator">:=</span> <span class="token keyword">func</span><span class="token punctuation">(</span>err <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>pretaskhandler <span class="token operator">:=</span> <span class="token keyword">func</span><span class="token punctuation">(</span>signature <span class="token operator">*</span>tasks<span class="token punctuation">.</span>Signature<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>posttaskhandler <span class="token operator">:=</span> <span class="token keyword">func</span><span class="token punctuation">(</span>signature <span class="token operator">*</span>tasks<span class="token punctuation">.</span>Signature<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>worker<span class="token punctuation">.</span><span class="token function">SetPostTaskHandler</span><span class="token punctuation">(</span>posttaskhandler<span class="token punctuation">)</span>worker<span class="token punctuation">.</span><span class="token function">SetErrorHandler</span><span class="token punctuation">(</span>errorhandler<span class="token punctuation">)</span>worker<span class="token punctuation">.</span><span class="token function">SetPreTaskHandler</span><span class="token punctuation">(</span>pretaskhandler<span class="token punctuation">)</span><span class="token keyword">return</span> worker<span class="token punctuation">.</span><span class="token function">Launch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 第三步:添加异步执行函数</span><span class="token keyword">func</span> <span class="token function">Add</span><span class="token punctuation">(</span>args <span class="token operator">...</span><span class="token builtin">int64</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">int64</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"############# 执行Add方法 #############"</span><span class="token punctuation">)</span>sum <span class="token operator">:=</span> <span class="token function">int64</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> arg <span class="token operator">:=</span> <span class="token keyword">range</span> args <span class="token punctuation">{</span>sum <span class="token operator">+=</span> arg<span class="token punctuation">}</span><span class="token keyword">return</span> sum<span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">}</span><span class="token comment">// 第四步:添加一个周期性任务</span><span class="token keyword">func</span> <span class="token function">PeriodicTask</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"################ 执行周期任务PeriodicTask #################"</span><span class="token punctuation">)</span><span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-2-启动服务并发送任务"><a href="#2-2-启动服务并发送任务" class="headerlink" title="2.2 启动服务并发送任务"></a>2.2 启动服务并发送任务</h3><blockquote><ul><li>go run main.go worker // 启动worker服务</li><li>go run main.go // 发送任务到worker</li></ul></blockquote><p><img src="/img/image-20220206111935400.8a7a4509.png"></p><h2 id="03-gin-machinery"><a href="#03-gin-machinery" class="headerlink" title="03.gin+machinery"></a>03.gin+machinery</h2><h3 id="3-0-项目结构"><a href="#3-0-项目结构" class="headerlink" title="3.0 项目结构"></a>3.0 项目结构</h3><blockquote><p>go run main.go // 直接执行即可测试</p></blockquote><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go">xiaonaiqiang1@ZBMac<span class="token operator">-</span>C02CW08SM work <span class="token operator">%</span> tree ginWorker ginWorker├── main<span class="token punctuation">.</span><span class="token keyword">go</span> <span class="token comment">// 项目入库</span>└── pkg └── task ├── server<span class="token punctuation">.</span><span class="token keyword">go</span> <span class="token comment">// machinery服务初始化</span> ├── start<span class="token punctuation">.</span><span class="token keyword">go</span> <span class="token comment">// 启动异步任务入口</span> ├── cronJobs<span class="token punctuation">.</span><span class="token keyword">go</span> <span class="token comment">// 触发周期性任务</span> ├── sendJobs<span class="token punctuation">.</span><span class="token keyword">go</span> <span class="token comment">// 触发异任务</span> └── workers └── tasks<span class="token punctuation">.</span><span class="token keyword">go</span> <span class="token comment">// 定义执行任务函数</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="3-1-main-go"><a href="#3-1-main-go" class="headerlink" title="3.1 main.go"></a>3.1 main.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"ginWorker/pkg/task"</span><span class="token string">"github.com/gin-gonic/gin"</span><span class="token string">"net/http"</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">go</span> task<span class="token punctuation">.</span><span class="token function">Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 启动异步任务worker</span><span class="token keyword">go</span> task<span class="token punctuation">.</span><span class="token function">StartCron</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 启动定时任务</span>r <span class="token operator">:=</span> gin<span class="token punctuation">.</span><span class="token function">Default</span><span class="token punctuation">(</span><span class="token punctuation">)</span>r<span class="token punctuation">.</span><span class="token function">GET</span><span class="token punctuation">(</span><span class="token string">"/add"</span><span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>c <span class="token operator">*</span>gin<span class="token punctuation">.</span>Context<span class="token punctuation">)</span> <span class="token punctuation">{</span>task<span class="token punctuation">.</span><span class="token function">TaskAdd</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">)</span> <span class="token comment">// 测试执行异步任务</span>c<span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusOK<span class="token punctuation">,</span> <span class="token string">"hello word"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"http://127.0.0.1:8000"</span><span class="token punctuation">)</span><span class="token comment">//监听端口默认为8080</span>r<span class="token punctuation">.</span><span class="token function">Run</span><span class="token punctuation">(</span><span class="token string">":8000"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="3-2-pkg-x2F-task-x2F-server-go"><a href="#3-2-pkg-x2F-task-x2F-server-go" class="headerlink" title="3.2 pkg/task/server.go"></a>3.2 pkg/task/server.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> task<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"ginWorker/pkg/task/workers"</span><span class="token string">"github.com/RichardKnop/machinery/v2"</span>redisbackend <span class="token string">"github.com/RichardKnop/machinery/v2/backends/redis"</span>redisbroker <span class="token string">"github.com/RichardKnop/machinery/v2/brokers/redis"</span><span class="token string">"github.com/RichardKnop/machinery/v2/config"</span>eagerlock <span class="token string">"github.com/RichardKnop/machinery/v2/locks/eager"</span><span class="token string">"github.com/RichardKnop/machinery/v2/tasks"</span><span class="token punctuation">)</span><span class="token keyword">var</span> AsyncTaskCenter <span class="token operator">*</span>machinery<span class="token punctuation">.</span>Server<span class="token comment">// 第一:配置Server并注册任务</span><span class="token keyword">func</span> <span class="token function">startServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token operator">*</span>machinery<span class="token punctuation">.</span>Server<span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>cnf <span class="token operator">:=</span> <span class="token operator">&</span>config<span class="token punctuation">.</span>Config<span class="token punctuation">{</span>DefaultQueue<span class="token punctuation">:</span> <span class="token string">"machinery_tasks"</span><span class="token punctuation">,</span>ResultsExpireIn<span class="token punctuation">:</span> <span class="token number">3600</span><span class="token punctuation">,</span>Redis<span class="token punctuation">:</span> <span class="token operator">&</span>config<span class="token punctuation">.</span>RedisConfig<span class="token punctuation">{</span>MaxIdle<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span>IdleTimeout<span class="token punctuation">:</span> <span class="token number">240</span><span class="token punctuation">,</span>ReadTimeout<span class="token punctuation">:</span> <span class="token number">15</span><span class="token punctuation">,</span>WriteTimeout<span class="token punctuation">:</span> <span class="token number">15</span><span class="token punctuation">,</span>ConnectTimeout<span class="token punctuation">:</span> <span class="token number">15</span><span class="token punctuation">,</span>NormalTasksPollPeriod<span class="token punctuation">:</span> <span class="token number">1000</span><span class="token punctuation">,</span>DelayedTasksPollPeriod<span class="token punctuation">:</span> <span class="token number">500</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token comment">// 创建服务器实例</span>broker <span class="token operator">:=</span> redisbroker<span class="token punctuation">.</span><span class="token function">NewGR</span><span class="token punctuation">(</span>cnf<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token string">"localhost:6379"</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>backend <span class="token operator">:=</span> redisbackend<span class="token punctuation">.</span><span class="token function">NewGR</span><span class="token punctuation">(</span>cnf<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token string">"localhost:6379"</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>lock <span class="token operator">:=</span> eagerlock<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span>server <span class="token operator">:=</span> machinery<span class="token punctuation">.</span><span class="token function">NewServer</span><span class="token punctuation">(</span>cnf<span class="token punctuation">,</span> broker<span class="token punctuation">,</span> backend<span class="token punctuation">,</span> lock<span class="token punctuation">)</span>tasksMap <span class="token operator">:=</span> <span class="token function">initAsyncTaskMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span>AsyncTaskCenter <span class="token operator">=</span> server<span class="token keyword">return</span> server<span class="token punctuation">,</span> server<span class="token punctuation">.</span><span class="token function">RegisterTasks</span><span class="token punctuation">(</span>tasksMap<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 第二步:启动Worker</span><span class="token keyword">func</span> <span class="token function">worker</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>consumerTag <span class="token operator">:=</span> <span class="token string">"machinery_worker"</span><span class="token comment">//消费者的标记</span>server<span class="token punctuation">,</span> err <span class="token operator">:=</span> <span class="token function">startServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span><span class="token keyword">return</span> err<span class="token punctuation">}</span>worker <span class="token operator">:=</span> server<span class="token punctuation">.</span><span class="token function">NewWorker</span><span class="token punctuation">(</span>consumerTag<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token comment">//第二个参数并发数, 0表示不限制</span><span class="token comment">//钩子函数</span>errorhandler <span class="token operator">:=</span> <span class="token keyword">func</span><span class="token punctuation">(</span>err <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>pretaskhandler <span class="token operator">:=</span> <span class="token keyword">func</span><span class="token punctuation">(</span>signature <span class="token operator">*</span>tasks<span class="token punctuation">.</span>Signature<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>posttaskhandler <span class="token operator">:=</span> <span class="token keyword">func</span><span class="token punctuation">(</span>signature <span class="token operator">*</span>tasks<span class="token punctuation">.</span>Signature<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>worker<span class="token punctuation">.</span><span class="token function">SetPostTaskHandler</span><span class="token punctuation">(</span>posttaskhandler<span class="token punctuation">)</span>worker<span class="token punctuation">.</span><span class="token function">SetErrorHandler</span><span class="token punctuation">(</span>errorhandler<span class="token punctuation">)</span>worker<span class="token punctuation">.</span><span class="token function">SetPreTaskHandler</span><span class="token punctuation">(</span>pretaskhandler<span class="token punctuation">)</span><span class="token keyword">return</span> worker<span class="token punctuation">.</span><span class="token function">Launch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 第三步:注册函数</span><span class="token keyword">func</span> <span class="token function">initAsyncTaskMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span><span class="token keyword">interface</span><span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">{</span>tasksMap <span class="token operator">:=</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span><span class="token keyword">interface</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">{</span><span class="token string">"add"</span><span class="token punctuation">:</span> workers<span class="token punctuation">.</span>Add<span class="token punctuation">,</span><span class="token string">"periodicTask"</span><span class="token punctuation">:</span> workers<span class="token punctuation">.</span>PeriodicTask<span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token keyword">return</span> tasksMap<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="3-3-pkg-x2F-task-x2F-start-go"><a href="#3-3-pkg-x2F-task-x2F-start-go" class="headerlink" title="3.3 pkg/task/start.go"></a>3.3 pkg/task/start.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> task<span class="token keyword">func</span> <span class="token function">Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 启动worker</span><span class="token keyword">if</span> err <span class="token operator">:=</span> <span class="token function">worker</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span><span class="token function">panic</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// 启动周期性任务</span><span class="token keyword">func</span> <span class="token function">StartCron</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">TestPeriodicTask</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="3-4-pkg-x2F-task-x2F-cronJobs-go"><a href="#3-4-pkg-x2F-task-x2F-cronJobs-go" class="headerlink" title="3.4 pkg/task/cronJobs.go"></a>3.4 pkg/task/cronJobs.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> task<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"github.com/RichardKnop/machinery/v2/tasks"</span><span class="token punctuation">)</span><span class="token comment">/* 触发执行periodicTask异步任务 */</span><span class="token keyword">func</span> <span class="token function">TestPeriodicTask</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>server<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> <span class="token function">startServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>signature <span class="token operator">:=</span> <span class="token operator">&</span>tasks<span class="token punctuation">.</span>Signature<span class="token punctuation">{</span>Name<span class="token punctuation">:</span> <span class="token string">"periodicTask"</span><span class="token punctuation">,</span>Args<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>tasks<span class="token punctuation">.</span>Arg<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token comment">// 每分钟执行一次periodicTask函数,验证发现不支持秒级别定时任务</span>err <span class="token operator">:=</span> server<span class="token punctuation">.</span><span class="token function">RegisterPeriodicTask</span><span class="token punctuation">(</span><span class="token string">"*/1 * * * ?"</span><span class="token punctuation">,</span> <span class="token string">"periodic-task"</span><span class="token punctuation">,</span> signature<span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">}</span>asyncResult<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> server<span class="token punctuation">.</span><span class="token function">SendTask</span><span class="token punctuation">(</span>signature<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>asyncResult<span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="3-5-pkg-x2F-task-x2F-sendJobs-go"><a href="#3-5-pkg-x2F-task-x2F-sendJobs-go" class="headerlink" title="3.5 pkg/task/sendJobs.go"></a>3.5 pkg/task/sendJobs.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> task<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"github.com/RichardKnop/machinery/v2/tasks"</span><span class="token punctuation">)</span><span class="token comment">/* 触发执行Add异步任务 */</span><span class="token keyword">func</span> <span class="token function">TaskAdd</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span>b <span class="token builtin">int64</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>signature <span class="token operator">:=</span> <span class="token operator">&</span>tasks<span class="token punctuation">.</span>Signature<span class="token punctuation">{</span>Name<span class="token punctuation">:</span> <span class="token string">"add"</span><span class="token punctuation">,</span>Args<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>tasks<span class="token punctuation">.</span>Arg<span class="token punctuation">{</span><span class="token punctuation">{</span>Type<span class="token punctuation">:</span> <span class="token string">"int64"</span><span class="token punctuation">,</span>Value<span class="token punctuation">:</span> a<span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">{</span>Type<span class="token punctuation">:</span> <span class="token string">"int64"</span><span class="token punctuation">,</span>Value<span class="token punctuation">:</span> b<span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token boolean">_</span><span class="token punctuation">,</span> err <span class="token operator">:=</span> AsyncTaskCenter<span class="token punctuation">.</span><span class="token function">SendTask</span><span class="token punctuation">(</span>signature<span class="token punctuation">)</span> <span class="token comment">// 任务可以通过将Signature的实例传递给Server实例来调用</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="3-6-pkg-x2F-task-x2F-workers-x2F-tasks-go"><a href="#3-6-pkg-x2F-task-x2F-workers-x2F-tasks-go" class="headerlink" title="3.6 pkg/task/workers/tasks.go"></a>3.6 pkg/task/workers/tasks.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> workers<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"time"</span><span class="token punctuation">)</span><span class="token comment">// 添加异步执行函数</span><span class="token keyword">func</span> <span class="token function">Add</span><span class="token punctuation">(</span>args <span class="token operator">...</span><span class="token builtin">int64</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">int64</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"############# 执行Add方法 #############"</span><span class="token punctuation">)</span>time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span><span class="token number">10</span> <span class="token operator">*</span> time<span class="token punctuation">.</span>Second<span class="token punctuation">)</span> <span class="token comment">// 模拟执行耗时任务</span>sum <span class="token operator">:=</span> <span class="token function">int64</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> arg <span class="token operator">:=</span> <span class="token keyword">range</span> args <span class="token punctuation">{</span>sum <span class="token operator">+=</span> arg<span class="token punctuation">}</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"############# Add方法Done #############"</span><span class="token punctuation">)</span><span class="token keyword">return</span> sum<span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">}</span><span class="token comment">// 添加一个周期性任务</span><span class="token keyword">func</span> <span class="token function">PeriodicTask</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"################ 执行周期任务PeriodicTask #################"</span><span class="token punctuation">)</span><span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="3-7-运行结果"><a href="#3-7-运行结果" class="headerlink" title="3.7 运行结果"></a>3.7 运行结果</h3><ul><li><code>执行周期任务:每秒执行一次</code></li></ul><p><img src="/img/image-20220206112020324.6a282832.png"></p><ul><li><figure><div class="code-wrapper"><pre class="language-none"><code class="language-none">通过接口触发异步任务</code></pre></div></figure><ul><li><a href="http://127.0.0.1:8000/add">http://127.0.0.1:8000/add</a></li></ul></li></ul><p><img src="/img/image-20220206112110293.6b3d47fc.png"></p>]]></content>
<summary type="html"><h1 id="20-machinery"><a href="#20-machinery" class="headerlink" title="20.machinery"></a>20.machinery</h1><h2 id="01-异步框架machinery"><a href</summary>
<category term="Go常用库" scheme="http://coderedeng.github.io/categories/Go%E5%B8%B8%E7%94%A8%E5%BA%93/"/>
<category term="Go常用库" scheme="http://coderedeng.github.io/tags/Go%E5%B8%B8%E7%94%A8%E5%BA%93/"/>
</entry>
<entry>
<title>cron</title>
<link href="http://coderedeng.github.io/2022/06/21/Go%E5%B8%B8%E7%94%A8%E5%BA%93%E4%BB%8B%E7%BB%8D%20-%20cron/"/>
<id>http://coderedeng.github.io/2022/06/21/Go%E5%B8%B8%E7%94%A8%E5%BA%93%E4%BB%8B%E7%BB%8D%20-%20cron/</id>
<published>2022-06-21T13:24:57.000Z</published>
<updated>2026-06-07T01:21:54.895Z</updated>
<content type="html"><![CDATA[<h1 id="19-cron定时"><a href="#19-cron定时" class="headerlink" title="19.cron定时"></a>19.cron定时</h1><h2 id="01-cron基本使用"><a href="#01-cron基本使用" class="headerlink" title="01.cron基本使用"></a>01.cron基本使用</h2><h3 id="1-1-使用举例"><a href="#1-1-使用举例" class="headerlink" title="1.1 使用举例"></a>1.1 使用举例</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"github.com/robfig/cron"</span><span class="token punctuation">)</span><span class="token comment">//主函数</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>cron2 <span class="token operator">:=</span> cron<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//创建一个cron实例</span><span class="token comment">//执行定时任务(每5秒执行一次)</span>err<span class="token operator">:=</span> cron2<span class="token punctuation">.</span><span class="token function">AddFunc</span><span class="token punctuation">(</span><span class="token string">"*/5 * * * * *"</span><span class="token punctuation">,</span> print5<span class="token punctuation">)</span><span class="token keyword">if</span> err<span class="token operator">!=</span><span class="token boolean">nil</span><span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">//启动/关闭</span>cron2<span class="token punctuation">.</span><span class="token function">Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">defer</span> cron2<span class="token punctuation">.</span><span class="token function">Stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">select</span> <span class="token punctuation">{</span> <span class="token comment">//查询语句,保持程序运行,在这里等同于for{}</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">//执行函数</span><span class="token keyword">func</span> <span class="token function">print5</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"每5s执行一次cron"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="1-2-配置"><a href="#1-2-配置" class="headerlink" title="1.2 配置"></a>1.2 配置</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go">┌─────────────second 范围 <span class="token punctuation">(</span><span class="token number">0</span> <span class="token operator">-</span> <span class="token number">60</span><span class="token punctuation">)</span>│ ┌───────────── min <span class="token punctuation">(</span><span class="token number">0</span> <span class="token operator">-</span> <span class="token number">59</span><span class="token punctuation">)</span>│ │ ┌────────────── hour <span class="token punctuation">(</span><span class="token number">0</span> <span class="token operator">-</span> <span class="token number">23</span><span class="token punctuation">)</span>│ │ │ ┌─────────────── day of month <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">-</span> <span class="token number">31</span><span class="token punctuation">)</span>│ │ │ │ ┌──────────────── month <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">-</span> <span class="token number">12</span><span class="token punctuation">)</span>│ │ │ │ │ ┌───────────────── day of week <span class="token punctuation">(</span><span class="token number">0</span> <span class="token operator">-</span> <span class="token number">6</span><span class="token punctuation">)</span>│ │ │ │ │ ││ │ │ │ │ │<span class="token operator">*</span> <span class="token operator">*</span> <span class="token operator">*</span> <span class="token operator">*</span> <span class="token operator">*</span> <span class="token operator">*</span> <span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="1-3-多个crontab任务"><a href="#1-3-多个crontab任务" class="headerlink" title="1.3 多个crontab任务"></a>1.3 多个crontab任务</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"github.com/robfig/cron"</span><span class="token punctuation">)</span><span class="token keyword">type</span> TestJob <span class="token keyword">struct</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token punctuation">(</span>this TestJob<span class="token punctuation">)</span> <span class="token function">Run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"testJob1..."</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">type</span> Test2Job <span class="token keyword">struct</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token punctuation">(</span>this Test2Job<span class="token punctuation">)</span> <span class="token function">Run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"testJob2..."</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">//启动多个任务</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>c <span class="token operator">:=</span> cron<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span>spec <span class="token operator">:=</span> <span class="token string">"*/5 * * * * ?"</span><span class="token comment">//AddJob方法</span>c<span class="token punctuation">.</span><span class="token function">AddJob</span><span class="token punctuation">(</span>spec<span class="token punctuation">,</span> TestJob<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>c<span class="token punctuation">.</span><span class="token function">AddJob</span><span class="token punctuation">(</span>spec<span class="token punctuation">,</span> Test2Job<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token comment">//启动计划任务</span>c<span class="token punctuation">.</span><span class="token function">Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">//关闭着计划任务, 但是不能关闭已经在执行中的任务.</span><span class="token keyword">defer</span> c<span class="token punctuation">.</span><span class="token function">Stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">select</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">/*testJob1...testJob2...testJob1...testJob2...*/</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="02-gin框架cron应用"><a href="#02-gin框架cron应用" class="headerlink" title="02.gin框架cron应用"></a>02.gin框架cron应用</h2><ul><li>目录结构</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token punctuation">.</span>├── main<span class="token punctuation">.</span><span class="token keyword">go</span>└── pkg └── jobs ├── job_cron<span class="token punctuation">.</span><span class="token keyword">go</span> <span class="token comment">// 分布式任务配置</span> └── test_task<span class="token punctuation">.</span><span class="token keyword">go</span> <span class="token comment">// 具体任务实例</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-1-main-go"><a href="#2-1-main-go" class="headerlink" title="2.1 main.go"></a>2.1 main.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"go_cron_demo/pkg/jobs"</span><span class="token string">"net/http"</span><span class="token string">"github.com/gin-gonic/gin"</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>jobs<span class="token punctuation">.</span><span class="token function">InitJobs</span><span class="token punctuation">(</span><span class="token punctuation">)</span>r <span class="token operator">:=</span> gin<span class="token punctuation">.</span><span class="token function">Default</span><span class="token punctuation">(</span><span class="token punctuation">)</span>r<span class="token punctuation">.</span><span class="token function">GET</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>c <span class="token operator">*</span>gin<span class="token punctuation">.</span>Context<span class="token punctuation">)</span> <span class="token punctuation">{</span>c<span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusOK<span class="token punctuation">,</span> <span class="token string">"hello World!"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span>r<span class="token punctuation">.</span><span class="token function">Run</span><span class="token punctuation">(</span><span class="token string">":8000"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-2-pkg-x2F-jobs-x2F-job-cron-go"><a href="#2-2-pkg-x2F-jobs-x2F-job-cron-go" class="headerlink" title="2.2 pkg/jobs/job_cron.go"></a>2.2 pkg/jobs/job_cron.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> jobs<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"github.com/robfig/cron"</span><span class="token punctuation">)</span><span class="token keyword">var</span> mainCron <span class="token operator">*</span>cron<span class="token punctuation">.</span>Cron<span class="token keyword">func</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>mainCron <span class="token operator">=</span> cron<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span>mainCron<span class="token punctuation">.</span><span class="token function">Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">InitJobs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 每5s钟调度一次,并传参</span>mainCron<span class="token punctuation">.</span><span class="token function">AddJob</span><span class="token punctuation">(</span><span class="token string">"*/5 * * * * ?"</span><span class="token punctuation">,</span>TestJob<span class="token punctuation">{</span>Id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> Name<span class="token punctuation">:</span> <span class="token string">"zhangsan"</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">/* 运行结果1 zhangsantestJob1...1 zhangsantestJob1...*/</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-3-pkg-x2F-jobs-x2F-test-task-go"><a href="#2-3-pkg-x2F-jobs-x2F-test-task-go" class="headerlink" title="2.3 pkg/jobs/test_task.go"></a>2.3 pkg/jobs/test_task.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> jobs<span class="token keyword">import</span> <span class="token string">"fmt"</span><span class="token keyword">type</span> TestJob <span class="token keyword">struct</span> <span class="token punctuation">{</span>Id <span class="token builtin">int</span>Name <span class="token builtin">string</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token punctuation">(</span>this TestJob<span class="token punctuation">)</span> <span class="token function">Run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>this<span class="token punctuation">.</span>Id<span class="token punctuation">,</span> this<span class="token punctuation">.</span>Name<span class="token punctuation">)</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"testJob1..."</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure>]]></content>
<summary type="html"><h1 id="19-cron定时"><a href="#19-cron定时" class="headerlink" title="19.cron定时"></a>19.cron定时</h1><h2 id="01-cron基本使用"><a href="#01-cron基本使用" c</summary>
<category term="Go常用库" scheme="http://coderedeng.github.io/categories/Go%E5%B8%B8%E7%94%A8%E5%BA%93/"/>
<category term="Go常用库" scheme="http://coderedeng.github.io/tags/Go%E5%B8%B8%E7%94%A8%E5%BA%93/"/>
</entry>
<entry>
<title>logrus</title>
<link href="http://coderedeng.github.io/2022/06/20/Go%E5%B8%B8%E7%94%A8%E5%BA%93%E4%BB%8B%E7%BB%8D%20-%20logrus/"/>
<id>http://coderedeng.github.io/2022/06/20/Go%E5%B8%B8%E7%94%A8%E5%BA%93%E4%BB%8B%E7%BB%8D%20-%20logrus/</id>
<published>2022-06-20T13:54:53.000Z</published>
<updated>2026-06-07T01:21:54.895Z</updated>
<content type="html"><![CDATA[<h1 id="18-logrus"><a href="#18-logrus" class="headerlink" title="18.logrus"></a>18.logrus</h1><h2 id="01-logrus基础"><a href="#01-logrus基础" class="headerlink" title="01.logrus基础"></a>01.logrus基础</h2><ul><li><a href="https://github.com/sirupsen/logrus">参考GitHub(opens new window)</a></li><li><a href="https://blog.51cto.com/u_15183360/2737283">参考博客1(opens new window)</a></li><li><a href="https://www.liwenzhou.com/posts/Go/go_logrus/">参考博客2(opens new window)</a></li><li>安装</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">go get github.com/sirupsen/logrus<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div></figure><h3 id="1-1-简介"><a href="#1-1-简介" class="headerlink" title="1.1 简介"></a>1.1 简介</h3><blockquote><p>Logrus是Go(golang)的结构化logger,与标准库logger完全API兼容,它有以下特点</p></blockquote><ul><li>完全兼容标准日志库,拥有七种日志级别:<code>Trace</code>, <code>Debug</code>, <code>Info</code>, <code>Warning</code>, <code>Error</code>, <code>Fatal</code>and <code>Panic</code>。</li><li>可扩展的Hook机制,允许使用者通过Hook的方式将日志分发到任意地方<ul><li>如本地文件系统,logstash,elasticsearch或者mq等,或者通过Hook定义日志内容和格式等</li></ul></li><li>可选的日志输出格式,内置了两种日志格式JSONFormater和TextFormatter,还可以自定义日志格式</li><li>Field机制,通过Filed机制进行结构化的日志记录</li><li>线程安全</li></ul><h3 id="1-2-简单导报使用"><a href="#1-2-简单导报使用" class="headerlink" title="1.2 简单导报使用"></a>1.2 简单导报使用</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span>log <span class="token string">"github.com/sirupsen/logrus"</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>log<span class="token punctuation">.</span><span class="token function">WithFields</span><span class="token punctuation">(</span>log<span class="token punctuation">.</span>Fields<span class="token punctuation">{</span><span class="token string">"animal"</span><span class="token punctuation">:</span> <span class="token string">"dog"</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Info</span><span class="token punctuation">(</span><span class="token string">"测试info日志"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// INFO[0000] 测试info日志 animal=dog</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="1-3-日志级别"><a href="#1-3-日志级别" class="headerlink" title="1.3 日志级别"></a>1.3 日志级别</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"github.com/sirupsen/logrus"</span><span class="token punctuation">)</span><span class="token comment">// 创建一个新的logger实例。可以创建任意多个。</span><span class="token keyword">var</span> log <span class="token operator">=</span> logrus<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>log<span class="token punctuation">.</span><span class="token function">Trace</span><span class="token punctuation">(</span><span class="token string">"Something very low level."</span><span class="token punctuation">)</span>log<span class="token punctuation">.</span><span class="token function">Debug</span><span class="token punctuation">(</span><span class="token string">"Useful debugging information."</span><span class="token punctuation">)</span>log<span class="token punctuation">.</span><span class="token function">Info</span><span class="token punctuation">(</span><span class="token string">"Something noteworthy happened!"</span><span class="token punctuation">)</span>log<span class="token punctuation">.</span><span class="token function">Warn</span><span class="token punctuation">(</span><span class="token string">"You should probably take a look at this."</span><span class="token punctuation">)</span>log<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span><span class="token string">"Something failed but I'm not quitting."</span><span class="token punctuation">)</span><span class="token comment">// 记完日志后会调用os.Exit(1)</span>log<span class="token punctuation">.</span><span class="token function">Fatal</span><span class="token punctuation">(</span><span class="token string">"Bye."</span><span class="token punctuation">)</span><span class="token comment">// 记完日志后会调用 panic()</span>log<span class="token punctuation">.</span><span class="token function">Panic</span><span class="token punctuation">(</span><span class="token string">"I'm bailing."</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">/*INFO[0000] Something noteworthy happened!WARN[0000] You should probably take a look at this.ERRO[0000] Something failed but I'm not quitting.FATA[0000] Bye.*/</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="1-4-设置日志级别"><a href="#1-4-设置日志级别" class="headerlink" title="1.4 设置日志级别"></a>1.4 设置日志级别</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token comment">// 会记录info及以上级别 (warn, error, fatal, panic)</span>log<span class="token punctuation">.</span><span class="token function">SetLevel</span><span class="token punctuation">(</span>log<span class="token punctuation">.</span>InfoLevel<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div></figure><h3 id="1-5-字段"><a href="#1-5-字段" class="headerlink" title="1.5 字段"></a>1.5 字段</h3><ul><li>Logrus鼓励通过日志字段进行谨慎的结构化日志记录,而不是冗长的、不可解析的错误消息。</li><li>例如,区别于使用<code>log.Fatalf("Failed to send event %s to topic %s with key %d")</code></li><li>你应该使用如下方式记录更容易发现的内容</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span>log <span class="token string">"github.com/sirupsen/logrus"</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>log<span class="token punctuation">.</span><span class="token function">WithFields</span><span class="token punctuation">(</span>log<span class="token punctuation">.</span>Fields<span class="token punctuation">{</span><span class="token string">"event"</span><span class="token punctuation">:</span> <span class="token string">"event"</span><span class="token punctuation">,</span><span class="token string">"topic"</span><span class="token punctuation">:</span> <span class="token string">"topic"</span><span class="token punctuation">,</span><span class="token string">"key"</span><span class="token punctuation">:</span> <span class="token string">"key"</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Fatal</span><span class="token punctuation">(</span><span class="token string">"Failed to send event"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// FATA[0000] Failed to send event event=event key=key topic=topic</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="1-6-默认字段"><a href="#1-6-默认字段" class="headerlink" title="1.6 默认字段"></a>1.6 默认字段</h3><ul><li>通常,将一些字段始终附加到应用程序的全部或部分的日志语句中会很有帮助。</li><li>例如,你可能希望始终在请求的上下文中记录<code>request_id</code>和<code>user_ip</code>。</li><li>区别于在每一行日志中写上<code>log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})</code></li><li>你可以向下面的示例代码一样创建一个<code>logrus.Entry</code>去传递这些字段。</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> log <span class="token string">"github.com/sirupsen/logrus"</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>requestLogger <span class="token operator">:=</span> log<span class="token punctuation">.</span><span class="token function">WithFields</span><span class="token punctuation">(</span>log<span class="token punctuation">.</span>Fields<span class="token punctuation">{</span><span class="token string">"request_id"</span><span class="token punctuation">:</span> <span class="token string">"request_id"</span><span class="token punctuation">,</span> <span class="token string">"user_ip"</span><span class="token punctuation">:</span> <span class="token string">"user_ip"</span><span class="token punctuation">}</span><span class="token punctuation">)</span>requestLogger<span class="token punctuation">.</span><span class="token function">Info</span><span class="token punctuation">(</span><span class="token string">"something happened on that request"</span><span class="token punctuation">)</span> <span class="token comment">// will log request_id and user_ip</span>requestLogger<span class="token punctuation">.</span><span class="token function">Warn</span><span class="token punctuation">(</span><span class="token string">"something not great happened"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">/*INFO[0000] something happened on that request request_id=request_id user_ip=user_ipWARN[0000] something not great happened request_id=request_id user_ip=user_ip */</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="1-7-Hooks"><a href="#1-7-Hooks" class="headerlink" title="1.7 Hooks"></a>1.7 Hooks</h3><ul><li>你可以添加日志级别的钩子(Hook)。</li><li>例如,向异常跟踪服务发送<code>Error</code>、<code>Fatal</code>和<code>Panic</code>、信息到StatsD或同时将日志发送到多个位置,例如syslog。</li><li>Logrus配有内置钩子,在<code>init</code>中添加这些内置钩子或你自定义的钩子</li><li><a href="https://github.com/sirupsen/logrus/blob/master/hooks/syslog/README.md">GitHub参考(opens new window)</a></li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span>log <span class="token string">"github.com/sirupsen/logrus"</span><span class="token string">"gopkg.in/gemnasium/logrus-airbrake-hook.v2"</span> <span class="token comment">// the package is named "airbrake"</span>logrus_syslog <span class="token string">"github.com/sirupsen/logrus/hooks/syslog"</span><span class="token string">"log/syslog"</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// Use the Airbrake hook to report errors that have Error severity or above to</span><span class="token comment">// an exception tracker. You can create custom hooks, see the Hooks section.</span>log<span class="token punctuation">.</span><span class="token function">AddHook</span><span class="token punctuation">(</span>airbrake<span class="token punctuation">.</span><span class="token function">NewHook</span><span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">,</span> <span class="token string">"xyz"</span><span class="token punctuation">,</span> <span class="token string">"production"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>hook<span class="token punctuation">,</span> err <span class="token operator">:=</span> logrus_syslog<span class="token punctuation">.</span><span class="token function">NewSyslogHook</span><span class="token punctuation">(</span><span class="token string">"udp"</span><span class="token punctuation">,</span> <span class="token string">"localhost:514"</span><span class="token punctuation">,</span> syslog<span class="token punctuation">.</span>LOG_INFO<span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>log<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span><span class="token string">"Unable to connect to local syslog daemon"</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>log<span class="token punctuation">.</span><span class="token function">AddHook</span><span class="token punctuation">(</span>hook<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="1-8-格式化"><a href="#1-8-格式化" class="headerlink" title="1.8 格式化"></a>1.8 格式化</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"github.com/sirupsen/logrus"</span><span class="token punctuation">)</span><span class="token keyword">var</span> log <span class="token operator">=</span> logrus<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>log<span class="token punctuation">.</span>Formatter <span class="token operator">=</span> <span class="token operator">&</span>logrus<span class="token punctuation">.</span>JSONFormatter<span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">//log.SetReportCaller(true) // 可以开启记录函数名,但是会消耗性能</span>log<span class="token punctuation">.</span><span class="token function">WithFields</span><span class="token punctuation">(</span>logrus<span class="token punctuation">.</span>Fields<span class="token punctuation">{</span><span class="token string">"event"</span><span class="token punctuation">:</span> <span class="token string">"event"</span><span class="token punctuation">,</span><span class="token string">"topic"</span><span class="token punctuation">:</span> <span class="token string">"topic"</span><span class="token punctuation">,</span><span class="token string">"key"</span><span class="token punctuation">:</span> <span class="token string">"key"</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Info</span><span class="token punctuation">(</span><span class="token string">"Failed to send event"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">/*{ "event":"event", "key":"key", "level":"info", "msg":"Failed to send event", "time":"2021-12-23T12:21:55+08:00", "topic":"topic"} */</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="1-9-gin中使用logrus"><a href="#1-9-gin中使用logrus" class="headerlink" title="1.9 gin中使用logrus"></a>1.9 gin中使用logrus</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"github.com/sirupsen/logrus"</span><span class="token string">"os"</span><span class="token string">"github.com/gin-gonic/gin"</span><span class="token punctuation">)</span><span class="token keyword">var</span> log <span class="token operator">=</span> logrus<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// Log as JSON instead of the default ASCII formatter.</span>log<span class="token punctuation">.</span>Formatter <span class="token operator">=</span> <span class="token operator">&</span>logrus<span class="token punctuation">.</span>JSONFormatter<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token comment">// Output to stdout instead of the default stderr</span><span class="token comment">// Can be any io.Writer, see below for File example</span>f<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> os<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span><span class="token string">"./gin.log"</span><span class="token punctuation">)</span>log<span class="token punctuation">.</span>Out <span class="token operator">=</span> fgin<span class="token punctuation">.</span><span class="token function">SetMode</span><span class="token punctuation">(</span>gin<span class="token punctuation">.</span>ReleaseMode<span class="token punctuation">)</span>gin<span class="token punctuation">.</span>DefaultWriter <span class="token operator">=</span> log<span class="token punctuation">.</span>Out<span class="token comment">// Only log the warning severity or above.</span>log<span class="token punctuation">.</span>Level <span class="token operator">=</span> logrus<span class="token punctuation">.</span>InfoLevel<span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 创建一个默认的路由引擎</span>r <span class="token operator">:=</span> gin<span class="token punctuation">.</span><span class="token function">Default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">// GET:请求方式;/hello:请求的路径</span><span class="token comment">// 当客户端以GET方法请求/hello路径时,会执行后面的匿名函数</span>r<span class="token punctuation">.</span><span class="token function">GET</span><span class="token punctuation">(</span><span class="token string">"/hello"</span><span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>c <span class="token operator">*</span>gin<span class="token punctuation">.</span>Context<span class="token punctuation">)</span> <span class="token punctuation">{</span>log<span class="token punctuation">.</span><span class="token function">WithFields</span><span class="token punctuation">(</span>logrus<span class="token punctuation">.</span>Fields<span class="token punctuation">{</span><span class="token string">"animal"</span><span class="token punctuation">:</span> <span class="token string">"walrus"</span><span class="token punctuation">,</span><span class="token string">"size"</span><span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Warn</span><span class="token punctuation">(</span><span class="token string">"A group of walrus emerges from the ocean"</span><span class="token punctuation">)</span><span class="token comment">// c.JSON:返回JSON格式的数据</span>c<span class="token punctuation">.</span><span class="token function">JSON</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">,</span> gin<span class="token punctuation">.</span>H<span class="token punctuation">{</span><span class="token string">"message"</span><span class="token punctuation">:</span> <span class="token string">"Hello world!"</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token comment">// 启动HTTP服务,默认在0.0.0.0:8080启动服务</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">`http://127.0.0.1:8080/hello`</span><span class="token punctuation">)</span>r<span class="token punctuation">.</span><span class="token function">Run</span><span class="token punctuation">(</span><span class="token string">":8080"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><ul><li>记录日志</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-text" data-language="text"><code class="language-text">{"animal":"walrus","level":"warning","msg":"A group of walrus emerges from the ocean","size":10,"time":"2021-12-23T12:37:21+08:00"}[GIN] 2021/12/23 - 12:37:21 | 200 | 705.823µs | 127.0.0.1 | GET "/hello"<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div></figure><h2 id="02-在gin中封装使用"><a href="#02-在gin中封装使用" class="headerlink" title="02.在gin中封装使用"></a>02.在gin中封装使用</h2><h3 id="2-0-目录结构"><a href="#2-0-目录结构" class="headerlink" title="2.0 目录结构"></a>2.0 目录结构</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go">logrus<span class="token operator">-</span>demo├── main<span class="token punctuation">.</span><span class="token keyword">go</span>└── middleware └── logger<span class="token punctuation">.</span><span class="token keyword">go</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-1-main-go"><a href="#2-1-main-go" class="headerlink" title="2.1 main.go"></a>2.1 main.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"cobra-demo/middleware"</span><span class="token string">"fmt"</span><span class="token string">"github.com/gin-gonic/gin"</span><span class="token string">"github.com/sirupsen/logrus"</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">helloWorld</span><span class="token punctuation">(</span>c <span class="token operator">*</span>gin<span class="token punctuation">.</span>Context<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 测试写入日志</span>middleware<span class="token punctuation">.</span>Logger<span class="token punctuation">.</span><span class="token function">WithFields</span><span class="token punctuation">(</span>logrus<span class="token punctuation">.</span>Fields<span class="token punctuation">{</span><span class="token string">"data"</span> <span class="token punctuation">:</span> <span class="token string">"访问/hello"</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Info</span><span class="token punctuation">(</span><span class="token string">"测试写入info"</span><span class="token punctuation">)</span><span class="token comment">// c.JSON:返回JSON格式的数据</span>c<span class="token punctuation">.</span><span class="token function">JSON</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">,</span> gin<span class="token punctuation">.</span>H<span class="token punctuation">{</span><span class="token string">"message"</span><span class="token punctuation">:</span> <span class="token string">"Hello world!"</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>r <span class="token operator">:=</span> gin<span class="token punctuation">.</span><span class="token function">Default</span><span class="token punctuation">(</span><span class="token punctuation">)</span>r<span class="token punctuation">.</span><span class="token function">Use</span><span class="token punctuation">(</span>middleware<span class="token punctuation">.</span><span class="token function">LoggerMiddleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>r<span class="token punctuation">.</span><span class="token function">GET</span><span class="token punctuation">(</span><span class="token string">"/hello"</span><span class="token punctuation">,</span> helloWorld<span class="token punctuation">)</span><span class="token comment">// 启动HTTP服务,默认在0.0.0.0:8080启动服务</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">`http://127.0.0.1:8080/hello`</span><span class="token punctuation">)</span>r<span class="token punctuation">.</span><span class="token function">Run</span><span class="token punctuation">(</span><span class="token string">":8080"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-2-middleware-x2F-logger-ge"><a href="#2-2-middleware-x2F-logger-ge" class="headerlink" title="2.2 middleware/logger.ge"></a>2.2 middleware/logger.ge</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> middleware<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"github.com/gin-gonic/gin"</span>rotatelogs <span class="token string">"github.com/lestrrat-go/file-rotatelogs"</span><span class="token string">"github.com/rifflock/lfshook"</span><span class="token string">"github.com/sirupsen/logrus"</span><span class="token string">"os"</span><span class="token string">"path"</span><span class="token string">"time"</span><span class="token punctuation">)</span><span class="token keyword">var</span> <span class="token punctuation">(</span>logFilePath <span class="token operator">=</span> <span class="token string">"./"</span>logFileName <span class="token operator">=</span> <span class="token string">"system.log"</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">LoggerMiddleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span> gin<span class="token punctuation">.</span>HandlerFunc <span class="token punctuation">{</span><span class="token comment">// 日志文件</span>fileName <span class="token operator">:=</span> path<span class="token punctuation">.</span><span class="token function">Join</span><span class="token punctuation">(</span>logFilePath<span class="token punctuation">,</span> logFileName<span class="token punctuation">)</span><span class="token comment">// 写入文件</span>src<span class="token punctuation">,</span> err <span class="token operator">:=</span> os<span class="token punctuation">.</span><span class="token function">OpenFile</span><span class="token punctuation">(</span>fileName<span class="token punctuation">,</span> os<span class="token punctuation">.</span>O_APPEND<span class="token operator">|</span>os<span class="token punctuation">.</span>O_WRONLY<span class="token punctuation">,</span> os<span class="token punctuation">.</span>ModeAppend<span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"err"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 实例化</span>logger <span class="token operator">:=</span> logrus<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">//设置日志级别</span>logger<span class="token punctuation">.</span><span class="token function">SetLevel</span><span class="token punctuation">(</span>logrus<span class="token punctuation">.</span>DebugLevel<span class="token punctuation">)</span><span class="token comment">//设置输出</span>logger<span class="token punctuation">.</span>Out <span class="token operator">=</span> src<span class="token comment">// 设置 rotatelogs</span>logWriter<span class="token punctuation">,</span> err <span class="token operator">:=</span> rotatelogs<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token comment">// 分割后的文件名称</span>fileName<span class="token operator">+</span><span class="token string">".%Y%m%d.log"</span><span class="token punctuation">,</span><span class="token comment">// 生成软链,指向最新日志文件</span>rotatelogs<span class="token punctuation">.</span><span class="token function">WithLinkName</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token comment">// 设置最大保存时间(7天)</span>rotatelogs<span class="token punctuation">.</span><span class="token function">WithMaxAge</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token operator">*</span><span class="token number">24</span><span class="token operator">*</span>time<span class="token punctuation">.</span>Hour<span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token comment">// 设置日志切割时间间隔(1天)</span>rotatelogs<span class="token punctuation">.</span><span class="token function">WithRotationTime</span><span class="token punctuation">(</span><span class="token number">24</span><span class="token operator">*</span>time<span class="token punctuation">.</span>Hour<span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token punctuation">)</span>writeMap <span class="token operator">:=</span> lfshook<span class="token punctuation">.</span>WriterMap<span class="token punctuation">{</span>logrus<span class="token punctuation">.</span>InfoLevel<span class="token punctuation">:</span> logWriter<span class="token punctuation">,</span>logrus<span class="token punctuation">.</span>FatalLevel<span class="token punctuation">:</span> logWriter<span class="token punctuation">,</span>logrus<span class="token punctuation">.</span>DebugLevel<span class="token punctuation">:</span> logWriter<span class="token punctuation">,</span>logrus<span class="token punctuation">.</span>WarnLevel<span class="token punctuation">:</span> logWriter<span class="token punctuation">,</span>logrus<span class="token punctuation">.</span>ErrorLevel<span class="token punctuation">:</span> logWriter<span class="token punctuation">,</span>logrus<span class="token punctuation">.</span>PanicLevel<span class="token punctuation">:</span> logWriter<span class="token punctuation">,</span><span class="token punctuation">}</span>logger<span class="token punctuation">.</span><span class="token function">AddHook</span><span class="token punctuation">(</span>lfshook<span class="token punctuation">.</span><span class="token function">NewHook</span><span class="token punctuation">(</span>writeMap<span class="token punctuation">,</span> <span class="token operator">&</span>logrus<span class="token punctuation">.</span>JSONFormatter<span class="token punctuation">{</span>TimestampFormat<span class="token punctuation">:</span> <span class="token string">"2006-01-02 15:04:05"</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">return</span> <span class="token keyword">func</span><span class="token punctuation">(</span>c <span class="token operator">*</span>gin<span class="token punctuation">.</span>Context<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//开始时间</span>startTime <span class="token operator">:=</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">//处理请求</span>c<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">//结束时间</span>endTime <span class="token operator">:=</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">// 执行时间</span>latencyTime <span class="token operator">:=</span> endTime<span class="token punctuation">.</span><span class="token function">Sub</span><span class="token punctuation">(</span>startTime<span class="token punctuation">)</span><span class="token comment">//请求方式</span>reqMethod <span class="token operator">:=</span> c<span class="token punctuation">.</span>Request<span class="token punctuation">.</span>Method<span class="token comment">//请求路由</span>reqUrl <span class="token operator">:=</span> c<span class="token punctuation">.</span>Request<span class="token punctuation">.</span>RequestURI<span class="token comment">//状态码</span>statusCode <span class="token operator">:=</span> c<span class="token punctuation">.</span>Writer<span class="token punctuation">.</span><span class="token function">Status</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">//请求ip</span>clientIP <span class="token operator">:=</span> c<span class="token punctuation">.</span><span class="token function">ClientIP</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">// 日志格式</span>logger<span class="token punctuation">.</span><span class="token function">WithFields</span><span class="token punctuation">(</span>logrus<span class="token punctuation">.</span>Fields<span class="token punctuation">{</span><span class="token string">"status_code"</span><span class="token punctuation">:</span> statusCode<span class="token punctuation">,</span><span class="token string">"latency_time"</span><span class="token punctuation">:</span> latencyTime<span class="token punctuation">,</span><span class="token string">"client_ip"</span><span class="token punctuation">:</span> clientIP<span class="token punctuation">,</span><span class="token string">"req_method"</span><span class="token punctuation">:</span> reqMethod<span class="token punctuation">,</span><span class="token string">"req_uri"</span><span class="token punctuation">:</span> reqUrl<span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Info</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-3-logging-x2F-logger-go"><a href="#2-3-logging-x2F-logger-go" class="headerlink" title="2.3 logging/logger.go"></a>2.3 logging/logger.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> logging<span class="token keyword">import</span> <span class="token punctuation">(</span>setting <span class="token string">"bamboo.com/pipeline/Go-assault-squad/config"</span><span class="token string">"fmt"</span><span class="token string">"github.com/sirupsen/logrus"</span><span class="token string">"os"</span><span class="token punctuation">)</span><span class="token keyword">var</span> WebLog <span class="token operator">*</span>logrus<span class="token punctuation">.</span>Logger<span class="token keyword">func</span> <span class="token function">Init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token function">initWebLog</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">initWebLog</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>WebLog <span class="token operator">=</span> <span class="token function">initLog</span><span class="token punctuation">(</span>setting<span class="token punctuation">.</span>Conf<span class="token punctuation">.</span>LogConfig<span class="token punctuation">.</span>WebLogName<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 初始化日志句柄</span><span class="token keyword">func</span> <span class="token function">initLog</span><span class="token punctuation">(</span>logFileName <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator">*</span>logrus<span class="token punctuation">.</span>Logger<span class="token punctuation">{</span>log <span class="token operator">:=</span> logrus<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token punctuation">)</span>log<span class="token punctuation">.</span>Formatter <span class="token operator">=</span> <span class="token operator">&</span>logrus<span class="token punctuation">.</span>JSONFormatter<span class="token punctuation">{</span>TimestampFormat<span class="token punctuation">:</span> <span class="token string">"2006-01-02 15:04:05"</span><span class="token punctuation">,</span><span class="token punctuation">}</span>logFilePath <span class="token operator">:=</span> setting<span class="token punctuation">.</span>Conf<span class="token punctuation">.</span>LogFilePathlogName <span class="token operator">:=</span> logFilePath <span class="token operator">+</span> logFileName<span class="token keyword">var</span> f <span class="token operator">*</span>os<span class="token punctuation">.</span>File<span class="token keyword">var</span> err <span class="token builtin">error</span><span class="token comment">//判断日志文件夹是否存在,不存在则创建</span><span class="token keyword">if</span> <span class="token boolean">_</span><span class="token punctuation">,</span> err <span class="token operator">:=</span> os<span class="token punctuation">.</span><span class="token function">Stat</span><span class="token punctuation">(</span>logFilePath<span class="token punctuation">)</span><span class="token punctuation">;</span> os<span class="token punctuation">.</span><span class="token function">IsNotExist</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>os<span class="token punctuation">.</span><span class="token function">MkdirAll</span><span class="token punctuation">(</span>logFilePath<span class="token punctuation">,</span> os<span class="token punctuation">.</span>ModePerm<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">//判断日志文件是否存在,不存在则创建,否则就直接打开</span><span class="token keyword">if</span> <span class="token boolean">_</span><span class="token punctuation">,</span> err <span class="token operator">:=</span> os<span class="token punctuation">.</span><span class="token function">Stat</span><span class="token punctuation">(</span>logName<span class="token punctuation">)</span><span class="token punctuation">;</span> os<span class="token punctuation">.</span><span class="token function">IsNotExist</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>f<span class="token punctuation">,</span> err <span class="token operator">=</span> os<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>logName<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>f<span class="token punctuation">,</span> err <span class="token operator">=</span> os<span class="token punctuation">.</span><span class="token function">OpenFile</span><span class="token punctuation">(</span>logName<span class="token punctuation">,</span>os<span class="token punctuation">.</span>O_APPEND<span class="token operator">|</span>os<span class="token punctuation">.</span>O_WRONLY<span class="token punctuation">,</span> os<span class="token punctuation">.</span>ModeAppend<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"open log file failed"</span><span class="token punctuation">)</span><span class="token punctuation">}</span>log<span class="token punctuation">.</span>Out <span class="token operator">=</span> flog<span class="token punctuation">.</span>Level <span class="token operator">=</span> logrus<span class="token punctuation">.</span>InfoLevel<span class="token keyword">return</span> log<span class="token punctuation">}</span><span class="token comment">/*---- 日志写入测试 ----WebLog.WithFields(logrus.Fields{"data" : "访问/hello",}).Info("测试写入info")---- 写入结构如下 ----{"data":"访问/hello","level":"info","msg":"测试写入info","time":"2021-12-29 18:15:54"} */</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-4-访问测试"><a href="#2-4-访问测试" class="headerlink" title="2.4 访问测试"></a>2.4 访问测试</h3><blockquote><p>go run main.go</p></blockquote><ul><li><a href="http://127.0.0.1:8080/hello">http://127.0.0.1:8080/hello</a></li><li>写入日志格式</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span><span class="token property">"data"</span><span class="token operator">:</span><span class="token string">"访问/hello"</span><span class="token punctuation">,</span><span class="token property">"level"</span><span class="token operator">:</span><span class="token string">"info"</span><span class="token punctuation">,</span><span class="token property">"msg"</span><span class="token operator">:</span><span class="token string">"测试写入info"</span><span class="token punctuation">,</span><span class="token property">"time"</span><span class="token operator">:</span><span class="token string">"2021-12-23 15:27:37"</span><span class="token punctuation">}</span><span class="token punctuation">{</span><span class="token property">"client_ip"</span><span class="token operator">:</span><span class="token string">"127.0.0.1"</span><span class="token punctuation">,</span><span class="token property">"latency_time"</span><span class="token operator">:</span><span class="token number">418116</span><span class="token punctuation">,</span><span class="token property">"level"</span><span class="token operator">:</span><span class="token string">"info"</span><span class="token punctuation">,</span><span class="token property">"msg"</span><span class="token operator">:</span><span class="token string">""</span><span class="token punctuation">,</span><span class="token property">"req_method"</span><span class="token operator">:</span><span class="token string">"GET"</span><span class="token punctuation">,</span><span class="token property">"req_uri"</span><span class="token operator">:</span><span class="token string">"/hello"</span><span class="token punctuation">,</span><span class="token property">"status_code"</span><span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">,</span><span class="token property">"time"</span><span class="token operator">:</span><span class="token string">"2021-12-23 15:27:37"</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div></figure>]]></content>
<summary type="html"><h1 id="18-logrus"><a href="#18-logrus" class="headerlink" title="18.logrus"></a>18.logrus</h1><h2 id="01-logrus基础"><a href="#01-logrus基础" c</summary>
<category term="Go常用库" scheme="http://coderedeng.github.io/categories/Go%E5%B8%B8%E7%94%A8%E5%BA%93/"/>
<category term="Go常用库" scheme="http://coderedeng.github.io/tags/Go%E5%B8%B8%E7%94%A8%E5%BA%93/"/>
</entry>
<entry>
<title>Cobor</title>
<link href="http://coderedeng.github.io/2022/06/19/Go%E5%B8%B8%E7%94%A8%E5%BA%93%E4%BB%8B%E7%BB%8D%20-%20cobor/"/>
<id>http://coderedeng.github.io/2022/06/19/Go%E5%B8%B8%E7%94%A8%E5%BA%93%E4%BB%8B%E7%BB%8D%20-%20cobor/</id>
<published>2022-06-19T14:26:53.000Z</published>
<updated>2026-06-07T01:21:54.895Z</updated>
<content type="html"><![CDATA[<h1 id="17-cobor"><a href="#17-cobor" class="headerlink" title="17.cobor"></a>17.cobor</h1><h2 id="01-cobra使用"><a href="#01-cobra使用" class="headerlink" title="01.cobra使用"></a>01.cobra使用</h2><ul><li>GitHub地址: <a href="https://github.com/spf13/cobra/blob/master/user_guide.md">https://github.com/spf13/cobra/blob/master/user_guide.md</a></li><li>参考博客:<a href="https://www.qikqiak.com/post/create-cli-app-with-cobra/">https://www.qikqiak.com/post/create-cli-app-with-cobra/</a></li><li>安装</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">go get <span class="token parameter variable">-u</span> github.com/spf13/cobra <span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div></figure><h3 id="1-1-基本使用"><a href="#1-1-基本使用" class="headerlink" title="1.1 基本使用"></a>1.1 基本使用</h3><ul><li>初始项目</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">mkdir</span> cobra-demo <span class="token operator">&&</span> <span class="token builtin class-name">cd</span> cobra-demo$ go mod init cobra-demo<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div></figure><ul><li>2)下载cobra</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 强烈推荐配置该环境变量</span>$ <span class="token builtin class-name">export</span> <span class="token assign-left variable">GOPROXY</span><span class="token operator">=</span>https://goproxy.cn$ go get <span class="token parameter variable">-u</span> github.com/spf13/cobra/cobra<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></div></figure><ul><li>3)<code>cobra init</code> 命令来初始化 CLI 应用的脚手架</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ cobra init<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div></figure><h3 id="1-2-初始化结构说明"><a href="#1-2-初始化结构说明" class="headerlink" title="1.2 初始化结构说明"></a>1.2 初始化结构说明</h3><ul><li>目录结构</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-text" data-language="text"><code class="language-text">├── cmd│ └── root.go└── main.go<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></div></figure><ul><li>main.go</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token string">"cobra-demo/cmd"</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>cmd<span class="token punctuation">.</span><span class="token function">Execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><ul><li>cmd/root.go</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> cmd<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"os"</span><span class="token string">"github.com/spf13/cobra"</span><span class="token punctuation">)</span><span class="token keyword">var</span> rootCmd <span class="token operator">=</span> <span class="token operator">&</span>cobra<span class="token punctuation">.</span>Command<span class="token punctuation">{</span>Use<span class="token punctuation">:</span> <span class="token string">"cobra-demo"</span><span class="token punctuation">,</span>Short<span class="token punctuation">:</span> <span class="token string">"A brief description of your application"</span><span class="token punctuation">,</span>Long<span class="token punctuation">:</span> Run<span class="token punctuation">:</span> <span class="token keyword">func</span><span class="token punctuation">(</span>cmd <span class="token operator">*</span>cobra<span class="token punctuation">.</span>Command<span class="token punctuation">,</span> args <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Hello Cobra CLI"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token comment">// 然后再执行 execute 方法</span><span class="token keyword">func</span> <span class="token function">Execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>err <span class="token operator">:=</span> rootCmd<span class="token punctuation">.</span><span class="token function">Execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>os<span class="token punctuation">.</span><span class="token function">Exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// 每当执行或者调用命令的时候,它都会先执行 init 函数中的所有函数</span><span class="token keyword">func</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>rootCmd<span class="token punctuation">.</span><span class="token function">Flags</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">BoolP</span><span class="token punctuation">(</span><span class="token string">"toggle"</span><span class="token punctuation">,</span> <span class="token string">"t"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token string">"Help message for toggle"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><ul><li><code>rootCmd</code> 根命令就会首先运行 <code>initConfig</code> 函数,当所有的初始化函数执行完成后,才会执行 <code>rootCmd</code> 的 <code>RUN: func</code> 执行函数</li><li>我们可以在 <code>initConfig</code> 函数里面添加一些 Debug 信息</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">func</span> <span class="token function">initConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"I'm inside initConfig function in cmd/root.go"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></div></figure><h2 id="02-cobra项目使用"><a href="#02-cobra项目使用" class="headerlink" title="02.cobra项目使用"></a>02.cobra项目使用</h2><h3 id="2-0-目录结构"><a href="#2-0-目录结构" class="headerlink" title="2.0 目录结构"></a>2.0 目录结构</h3><ul><li>目录结构</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">cobra-demo├── cmd│ ├── root.go│ └── serve.go└── main.go<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-1-main-go"><a href="#2-1-main-go" class="headerlink" title="2.1 main.go"></a>2.1 main.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> main<span class="token keyword">import</span> <span class="token string">"cobra-demo/cmd"</span><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>cmd<span class="token punctuation">.</span><span class="token function">Execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-2-cmd-x2F-root-go"><a href="#2-2-cmd-x2F-root-go" class="headerlink" title="2.2 cmd/root.go"></a>2.2 cmd/root.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> cmd<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"errors"</span><span class="token string">"github.com/spf13/cobra"</span><span class="token string">"log"</span><span class="token string">"os"</span><span class="token punctuation">)</span><span class="token keyword">var</span> rootCmd <span class="token operator">=</span> <span class="token operator">&</span>cobra<span class="token punctuation">.</span>Command<span class="token punctuation">{</span>Use<span class="token punctuation">:</span> <span class="token string">"demo"</span><span class="token punctuation">,</span> <span class="token comment">// 命令行时关键字</span>Short<span class="token punctuation">:</span> <span class="token string">"cobra demo example"</span><span class="token punctuation">,</span> <span class="token comment">// 命令简单描述</span>Long<span class="token punctuation">:</span> <span class="token string">`cobra demo example ....`</span><span class="token punctuation">,</span> <span class="token comment">// 命令详细描述</span>Args<span class="token punctuation">:</span> <span class="token keyword">func</span><span class="token punctuation">(</span>cmd <span class="token operator">*</span>cobra<span class="token punctuation">.</span>Command<span class="token punctuation">,</span> args <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token number">1</span> <span class="token punctuation">{</span><span class="token keyword">return</span> errors<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token string">"requires at least one arg"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">}</span><span class="token punctuation">,</span>PersistentPreRunE<span class="token punctuation">:</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token operator">*</span>cobra<span class="token punctuation">.</span>Command<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>Run<span class="token punctuation">:</span> <span class="token keyword">func</span><span class="token punctuation">(</span>cmd <span class="token operator">*</span>cobra<span class="token punctuation">.</span>Command<span class="token punctuation">,</span> args <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 钩子函数</span>usageStr <span class="token operator">:=</span> <span class="token string">`可以使用 -h 查看命令`</span>log<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"%s\n"</span><span class="token punctuation">,</span> usageStr<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token comment">// 第二步:然后再执行 execute 方法</span><span class="token keyword">func</span> <span class="token function">Execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>err <span class="token operator">:=</span> rootCmd<span class="token punctuation">.</span><span class="token function">Execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>os<span class="token punctuation">.</span><span class="token function">Exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// 第一步:每当执行或者调用命令的时候,它都会先执行 init 函数中的所有函数</span><span class="token keyword">func</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>rootCmd<span class="token punctuation">.</span><span class="token function">AddCommand</span><span class="token punctuation">(</span>StartCmd<span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-3-cmd-x2F-serve-go"><a href="#2-3-cmd-x2F-serve-go" class="headerlink" title="2.3 cmd/serve.go"></a>2.3 cmd/serve.go</h3><figure><div class="code-wrapper"><pre class="line-numbers language-go" data-language="go"><code class="language-go"><span class="token keyword">package</span> cmd<span class="token keyword">import</span> <span class="token punctuation">(</span><span class="token string">"fmt"</span><span class="token string">"github.com/spf13/cobra"</span><span class="token string">"log"</span><span class="token punctuation">)</span><span class="token keyword">var</span> <span class="token punctuation">(</span>config <span class="token builtin">string</span> <span class="token comment">// 启动配置文件位置</span>port <span class="token builtin">string</span> <span class="token comment">// 启动端口号</span>mode <span class="token builtin">string</span> <span class="token comment">// 启动模式</span>StartCmd <span class="token operator">=</span> <span class="token operator">&</span>cobra<span class="token punctuation">.</span>Command<span class="token punctuation">{</span><span class="token comment">// go run main.go server -c=config/settings.dev.yml</span>Use<span class="token punctuation">:</span> <span class="token string">"server"</span><span class="token punctuation">,</span> <span class="token comment">// 启动时要添加 server关键字</span>Short<span class="token punctuation">:</span> <span class="token string">"Start API server"</span><span class="token punctuation">,</span> <span class="token comment">// 对命令简单描述</span>Example<span class="token punctuation">:</span> <span class="token string">"ferry server config/settings.yml"</span><span class="token punctuation">,</span> <span class="token comment">// 运行命令例子</span>PreRun<span class="token punctuation">:</span> <span class="token keyword">func</span><span class="token punctuation">(</span>cmd <span class="token operator">*</span>cobra<span class="token punctuation">.</span>Command<span class="token punctuation">,</span> args <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 钩子函数,在RunE前执行</span><span class="token function">usage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span>RunE<span class="token punctuation">:</span> <span class="token keyword">func</span><span class="token punctuation">(</span>cmd <span class="token operator">*</span>cobra<span class="token punctuation">.</span>Command<span class="token punctuation">,</span> args <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span> <span class="token comment">// 钩子函数</span><span class="token keyword">return</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token keyword">func</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 为 Command 添加选项(flags)</span>StartCmd<span class="token punctuation">.</span><span class="token function">PersistentFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">StringVarP</span><span class="token punctuation">(</span><span class="token operator">&</span>config<span class="token punctuation">,</span> <span class="token string">"config"</span><span class="token punctuation">,</span> <span class="token string">"c"</span><span class="token punctuation">,</span> <span class="token string">"config/settings.yml"</span><span class="token punctuation">,</span> <span class="token string">"Start server with provided configuration file"</span><span class="token punctuation">)</span>StartCmd<span class="token punctuation">.</span><span class="token function">PersistentFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">StringVarP</span><span class="token punctuation">(</span><span class="token operator">&</span>port<span class="token punctuation">,</span> <span class="token string">"port"</span><span class="token punctuation">,</span> <span class="token string">"p"</span><span class="token punctuation">,</span> <span class="token string">"8002"</span><span class="token punctuation">,</span> <span class="token string">"Tcp port server listening on"</span><span class="token punctuation">)</span>StartCmd<span class="token punctuation">.</span><span class="token function">PersistentFlags</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">StringVarP</span><span class="token punctuation">(</span><span class="token operator">&</span>mode<span class="token punctuation">,</span> <span class="token string">"mode"</span><span class="token punctuation">,</span> <span class="token string">"m"</span><span class="token punctuation">,</span> <span class="token string">"dev"</span><span class="token punctuation">,</span> <span class="token string">"server mode ; eg:dev,test,prod"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 记录日志</span><span class="token keyword">func</span> <span class="token function">usage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>usageStr <span class="token operator">:=</span> <span class="token string">`starting api server`</span>log<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"%s\n"</span><span class="token punctuation">,</span> usageStr<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token comment">// 初始化项目</span><span class="token keyword">func</span> <span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 1. 读取配置</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"启动命令配置文件:"</span><span class="token punctuation">,</span>config<span class="token punctuation">)</span><span class="token comment">// 2. 初始化数据库链接</span><span class="token comment">// 3. 启动异步任务队列</span><span class="token punctuation">}</span><span class="token keyword">func</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span><span class="token comment">// 1.获取当前启动模式</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"启动命令当前模式:"</span><span class="token punctuation">,</span> mode<span class="token punctuation">)</span><span class="token comment">// 2.获取当前启动端口</span>fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"启动命令当前端口"</span><span class="token punctuation">,</span> port<span class="token punctuation">)</span><span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure><h3 id="2-4-运行测试"><a href="#2-4-运行测试" class="headerlink" title="2.4 运行测试"></a>2.4 运行测试</h3><ul><li>我们可以根据当前命令行传入的 <code>配置文件位置、端口号、启动模式</code> 来启动项目</li></ul><figure><div class="code-wrapper"><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">xiaonaiqiang1@ZBMac-C02CW08SM cobra-demo % go run main.go server <span class="token parameter variable">-c</span><span class="token operator">=</span>config/settings.dev.yml <span class="token parameter variable">-p</span><span class="token operator">=</span><span class="token number">8888</span> <span class="token parameter variable">-m</span><span class="token operator">=</span>release<span class="token number">2021</span>/12/23 <span class="token number">11</span>:09:12 starting api server启动命令配置文件: config/settings.dev.yml启动命令当前模式: release启动命令当前端口 <span class="token number">8888</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></figure>]]></content>
<summary type="html"><h1 id="17-cobor"><a href="#17-cobor" class="headerlink" title="17.cobor"></a>17.cobor</h1><h2 id="01-cobra使用"><a href="#01-cobra使用" class="</summary>
<category term="Go常用库" scheme="http://coderedeng.github.io/categories/Go%E5%B8%B8%E7%94%A8%E5%BA%93/"/>
<category term="Go常用库" scheme="http://coderedeng.github.io/tags/Go%E5%B8%B8%E7%94%A8%E5%BA%93/"/>
</entry>
</feed>