《Go Web编程实战派》打折促销中,欢迎抢购~

当当(🔥🔥🔥🔥🔥🔥 活动抢购中……):http://product.dangdang.com/29225055.html
京东(🔥🔥🔥🔥🔥🔥 活动抢购中……):https://item.jd.com/13200972.html
天猫(🔥🔥🔥🔥🔥🔥 活动抢购中……):https://detail.tmall.com/item.htm?id=643246918641
视频介绍链接:https://www.bilibili.com/video/BV1pF411t7iL?spm_id_from=333.999.0.0

1.本书特色
本书聚焦Go Web开发领域,对Go Web知识进行全面深入地讲解。本书有如下特色:

(1)一线技术,突出实战;
本书以实战为核心,贯穿整本书。所有代码采用Go最新版本编写。

(2)精雕细琢,阅读性强;
全书的语言经过多次打磨,力求精确。同时注重阅读体验,让没有任何基础的读者也可以很轻松的读懂书中的知识。

(3)零基础入门,循序渐进,实现快速从菜鸟向实战派高手迈进;
本书以Go入门级程序员为主要对象,初、中、高级程序员都可以从书中学到干货。先从Go的基础学起,然后学习Go核心的技术,再学Go的高级应用,然后再进行项目实战,最后介绍应用程序的Docker实战部署。全书从最基础的知识讲解一步一步到最核心的B2C电子商务系实战开发,真正帮助读者从基础入门向开发高手迈进。

(4)极客思维,极致效率;
本书以极客思维、深入Go语言底层进行探究,帮助读者了解背后原理。全书言简意赅,以帮助读者提升开发效率为导向,同时尽可能帮助读者缩短阅读本书的时间。

(5)由易到难,重难点标注并重点解析;
本书编排由易到难,内容基本覆盖Go Web的主流前沿技术。同时对重难点进行重点讲解,对易错点和注意点进行了提示说明,帮助读者克服学习过程中的困难。

(6)突出实战,快速突击;
本书的实例代码是绝大部分都是来自于最新的企业实战项目。对于购买本书的读者,所有的源代码均可以通过网上下载,直接下载即可运行,让读者通过实践来加深理解。

(7)实战方案,可直接二次开发进行实战部署;
本书全书以实战为主,所有的示例代码,拿来即可运行。特别是第9章,购买本书的读者可以直接获得B2C电子商务系统的全部源代码。可以直接作为电商项目进行二次开发,用于读者的项目。读者购买本书不仅可以学习本书的各种知识,也相当于购买一个最新版的Go语言电商系统解决方案及项目源码。

2.阅读本书,您能学到什么
系统学习Go语言基础知识;
掌握HTTP基本原理;
掌握Go Web 底层原理;
掌握Go访问MySQL、Redis、MongoDB的方法和技巧;
掌握Gorm、Beego ORM的使用方法和技巧;
掌握Go Socket编程的方法和技巧;
掌握用gRPC实现微服务调用;
掌握Go 文件处理的方法和技巧;
掌握Go JSON、XML生成与解析方法和技巧;
掌握Go正则表达式的处理方法和技巧;
掌握Go 日志处理的方法和技巧;
掌握从数据库中导出一个csv文件的实战法;
掌握Go并发编程的底层原理
掌握常见Go并发Web应用的实战开发方法和技巧
掌握Go开发并发的Web爬虫的方法和技巧
掌握Gin框架、Beego框架的使用方法和技巧;
掌握流行架构风格RESTful API接口开发;
掌握用Go开发OAuth2.0接口技巧;
掌握Elasticsearch的使用方法;
掌握微信支付、支付宝支付接口对接方法;
掌握Go语言开发的B2C电子商务系统开发的整个流程方案及源码;
掌握Docker实战部署方法;
掌握Docker Compose实战部署方法。
希望通过本书的学习,能够让读者快速、系统地掌握Go Web开发的各种方法和技巧,帮助读者在Go 语言Web开发中,快速从基础入门向精通级的实战派高手迈进。

《Go语言设计模式》出版啦,欢迎想学的朋友购买~

为什么需要设计模式

设计模式可以根据以前的实践和经验记录要采用的解决方案。在设计模式的实现过程中,需要使用多个软件组件共同实现某些功能。因此,设计模式加快了涉及多个组件的开发过程。开发者可以在对应解决方案的具体应用中使用熟悉的编程语言。例如,如果某个开发者熟悉Go语言,那么这个开发者可以使用Go语言开发相应的组件。

使用设计模式可以提高开发速度。设计模式提供了经过验证的开发范例,有助于节省时间,而不必在每次出现问题时都重新创建设计模式。

因为设计模式是为了修复已知问题而创建的,所以设计模式可以在软件开发过程中对其进行预测。

使用设计模式可以提高开发者的思维能力、编程能力和设计能力。

设计模式使程序设计更加标准化、代码编制更加工程化,从而提高软件的开发效率,缩短软件的开发周期。

使用设计模式设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。设计模式可以在多种情况下以具体方式使用,可以让系统在后期更容易维护和扩展。

Go语言组合模式的实战示例

(1)什么是组合模式

组合模式(Composite Pattern)是指将一组相似的对象当作一个单一对象的设计模式。

组合模式描述了一组对象,这些对象被视为相同类型对象的单个实例。组合模式可以将对象组合成树形结构,从而表示部分或整体的层次结构。

组合模式允许开发者拥有一个树形结构,并且要求树形结构中的每个节点都执行一项任务。组合模式的主要功能是在整个树形结构中递归调用方法并对结果进行汇总。

组合模式的树形结构图如图3-1所示。

根据图3-1可知,组合模式的角色组成如下。

  • 组件(Component):组合中的对象声明接口,主要用于访问和管理其子组件。组件会酌情为所有类通用的接口实现默认行为。
  • 叶节点(Leaf):定义组合中原始对象行为的类。叶节点表示组合中的叶对象。
  • 组合(Composite):又称为容器(Container),存储子组件并在组件接口中实现与子组件有关操作的类。
  • 客户端(Client):客户端可以通过组件接口操作组合中的对象,以及与树形结构中的所有项目交互。

图3-1

组合不知道其子项目所属的具体类,它只通过通用的组件接口与其子项目交互。组合在收到请求后会将工作分配给自己的子项目,然后处理中间结果,最后将最终结果返回给客户端。组合模式的UML类图如图3-2所示。

图3-2

(2)组合模式的使用场景

组合模式是应树形结构而生的,常见的使用场景如下。

  • 当客户需要忽略组合对象和单个对象之间的差异时,可以使用组合模式。如果开发者以相同的方式使用多个对象,并且用几乎相同的代码处理每个对象,那么使用组合模式是一个不错的选择。
  • 如果需要实现树形结构,则可以使用组合模式。只需要通过请求树的顶层对象,就可以对整棵树进行统一操作。在组合模式中,添加和删除树的节点非常方便,并且遵循开闭原则,如命令分发、多级目录呈现等树形结构数据操作。
  • 如果开发者希望客户端以统一的方式处理简单或复杂的元素,则可以使用组合模式。

(3)组合模式的实现方式

在使用组合模式前,需要先确保应用程序的核心模型能够以树形结构表示。组合模式的实现方式如下。

1)定义组件接口,示例代码如下:

//组件接口

type Component interface {

    Execute()

}

2)定义一个叶节点类,用于表示简单元素,并且定义叶节点类的相关方法。程序中可以有多个不同的叶节点类。示例代码如下:

//叶节点类,主要用于描述树形结构中的原始叶节点对象

type Leaf struct {

    value int

}

//创建一个新的叶节点对象

func NewLeaf(value int) *Leaf {

    return &Leaf{value}

}

//打印叶节点对象的值

func (l *Leaf) Execute() {

    fmt.Printf(“%v  “, l.value)

}

3)定义一个组合类,用于表示复杂元素。在该类中,创建一个数组成员变量,用于存储对其子元素的引用。该数组必须能够同时存储叶节点和组合,因此需要确保将其声明为组件接口类型。在实现组件接口中的方法时,组合应该将大部分工作交给其子元素完成。

//组合类

type Composite struct {

    children []Component

}

//创建一个新的组合对象

func NewComposite() *Composite {

    return &Composite{make([]Component, 0)}

}

4)在组合类中定义添加或删除子元素的方法。这些操作可以在组件接口中声明,但会违反接口隔离原则(Interface Segregation Principle,ISP),因为叶节点类中的这些方法为空。

提示:

接口隔离原则要求开发者尽量将臃肿庞大的接口拆分成更小、更具体的接口,使接口中只包含客户端感兴趣的方法。

将一个新组件添加到组合中,并且遍历组合子对象,示例代码如下:

//将一个新组件添加到组合中

func (c *Composite) Add(component Component) {

    c.children = append(c.children, component)

}

//遍历组合子对象

func (c *Composite) Execute() {

    for i := 0; i < len(c.children); i++ {

        c.children[i].Execute()

    }

}

5)创建客户端,示例代码如下:

package main

import “github.com/shirdonl/goDesignPattern/chapter3/composite/example”

func main() {

    composite := example.NewComposite()

    leaf1 := example.NewLeaf(99)

    composite.Add(leaf1)

    leaf2 := example.NewLeaf(100)

    composite.Add(leaf2)

    leaf3 := example.NewComposite()

    composite.Add(leaf3)

    composite.Execute()

}

//$ go run main.go

//99  100  

以上节选自《Go语言设计模式》3.1.1小节。

本书聚焦于Go语言设计模式的知识与应用。全书共6章,分别为设计模式入门、创建型设计模式、结构型设计模式、行为型设计模式、设计模式扩展、设计模式与软件架构。本书简洁而不失技术深度,内容覆盖Go语言的主流设计模式和软件架构,以极简的文字介绍了复杂的案例,是学习Go语言设计模式和软件架构的实用教程。该书已经出版发行,感兴趣的读者朋友欢迎通过如下方式购买。

《Go语言高级开发与实战》正式出版了,欢迎想学Go语言的朋友们京东搜索“Go语言高级开发与实战”购买

经过近2年的写作,《Go语言高级开发与实战》正式出版了,欢迎想学Go语言的朋友们京东搜索“Go语言高级开发与实战”购买!

购买链接如下(新品预售打折活动中):《Go语言高级开发与实战》(廖显东)【摘要 书评 试读】- 京东图书​item.jd.com/13594166.html

欢迎想学Go语言的朋友们京东搜索购买!

Go语言高级开发与实战聚焦Go语言的高级开发技巧和应用实战。全书共6章,分别为Go语言基础实战、Go语言高级编程技巧、Go Web编程、Go语言并发编程、分布式系统、Go语言秒杀系统实战。Go语言高级开发与实战简洁而不失技术深度,内容丰富全面,以极简的文字介绍了复杂的案例,是学习Go语言高级开发的实用教程。

Go语言高级开发与实战适合Go语言初学者、Go语言中高级开发人员、Web开发工程师阅读,还可作为大中专院校相关专业和培训学校师生的学习用书。

Go语言高级开发与实战特色

Go语言高级开发与实战聚焦Go语言高级开发的知识进行全面深入的讲解,具有如下特色。

1.一线技术,突出实战

Go语言高级开发与实战以实战为核心,一线技术贯穿整Go语言高级开发与实战,所有代码均采用Go语言最新版本(1.16.2)编写。

2.零基础入门,循序渐进

初、中、高级程序员都可以从本书中学到干货。先从Go语言的基础学起,再学习Go语言的核心技术,然后学Go语言的高级应用,最后再进行项目实战。全书从基础的知识讲解,一步一步到热门的秒杀系统实战开发,真正帮助读者实现从基础向开发实战高手的迈进。

3.极客思维,极致效率

Go语言高级开发与实战以极客思维来深入Go语言底层进行探究,帮助读者了解其背后的原理。全书言简意赅,以帮助读者提升开发效率为导向,同时尽可能帮助读者缩短阅读本书的时间。

4.由易到难,重难点标注并重点解析

Go语言高级开发与实战编排由易到难,内容基本覆盖Go 语言高级开发的主流前沿技术。同时对重难点进行重点讲解,对易错点和注意点进行了提示说明,帮助读者克服学习过程中的困难。

5.突出实战,关注前沿技术

Go语言高级开发与实战的实例代码绝大部分都是来自最新的企业实战项目。配套源代码可以直接下载运行,让读者通过实践来加深理解。

购买链接如下(新品预售打折活动中):《Go语言高级开发与实战》(廖显东)【摘要 书评 试读】- 京东图书​item.jd.com/13594166.html

欢迎想学Go语言的朋友们京东搜索购买!

欢迎关注公众号“源码大数据”,获取更多资源:

2021年会成为元宇宙元年吗

什么是元宇宙?2021年会成为元宇宙元年吗?

2021年进入倒数第两个月,元宇宙大爆炸一般的出现在了科技圈和大众的视野里。腾讯、字节跳动等纷纷进入相关领域,国外脸书、微软、英伟达等科技公司也均已入局。随着Facebook正式改名为Meta(中文译为元宇宙)彻底地引燃了大众的兴趣。

Facebook表示这算是重大品牌重塑计划的一部分。该公司表示,它将更好地“涵盖”它所做的事情,因为它将其影响范围从社交媒体扩展到虚拟现实 (VR) 等领域。创始人马克扎克伯格10月29日表示,Facebook 将其公司名称更改为 Meta,有效地将 Facebook 的同名服务降级为该公司的子公司之一,与 Instagram 和 WhatsApp 并列,而不是总体品牌。

而这其中最引人注意的就是扎克伯格提到的Metaversa-元宇宙,科技巨头竞相入局“元宇宙”究竟有何种魅力?元宇宙到底是什么?而这个世界为什么需要元宇宙?0

“元宇宙”源起

“那是超元域(元宇宙)的百老汇,超元域的香榭丽舍大道。它是一条灯火辉煌的主干道,反射在阿弘的目镜中,能够被眼睛看到,能够被缩小,被倒转。它并不真正存在,但此时,那里正有数百万人在街上往来穿行。”这是第一次元宇宙的概念在元宇宙前传《雪崩》中被准确描写出来,这一年是1992年。

至此,多元宇宙的世界逐渐打开。那么为什么说2021年会是元宇宙的元年呢,首先来说在2021年前的铺垫条件。2020年全世界面临了诸多挑战,这也成为了人类社会虚拟化的临界点。

首先疫情加速社会虚拟化,新冠疫情隔离政策下,全社会上网时长大幅增长,“宅经济”快速发展。因此,线上生活由原先短时期的例外状态成为了常态,由现实世界的补充变成了与现实世界的平行世界。

并且,大家对于元宇宙的认知发生转变,虚拟的并不是虚假的,更不是无关紧要的。其次,生活发生迁移,线上与线下打通,人类的现实生活开始大规模向虚拟世界迁移,人类成为现实与数字的两栖物种。

这些变化都为元宇宙的爆发蓄力,2021之所以可以被称为元宇宙元年,是因为‘元宇宙“呈现超出想象的爆发力,其背后是元宇宙要素的“群聚效应”近似1995年互联网所经历的“群聚效应”。

什么是元宇宙?

在现下的认知来看,元宇宙可能看起来像是虚拟现实 (VR) 的增强版——但有些人认为元宇宙可能是互联网的未来。事实上,人们相信元宇宙对和VR 之间的差距可能就像现代智能手机和1980 年代第一批笨重的手机之间的差距一样。

元宇宙的英文是metaverse, meta(超越)+universe(宇宙),元宇宙可以说是一个平行于现实世界,又独立于现实世界的虚拟空间,是映射现实世界的在线虚拟世界,是越来越真实的数字虚拟世界。

在 metaverse 中,用户可以使用耳机进入连接各种数字环境的虚拟世界,而不是在计算机上。与目前主要用于游戏的 VR 不同,这个虚拟世界几乎可以用于任何事情——工作、娱乐、音乐、约会、电影旅行——或者只是闲逛。

元宇宙是整合多种新技术而产生的新型虚实相融的互联网应用和社会形态,它基于扩展现实技术提供沉浸式体验,基于数字孪生技术生成现实世界的镜像,基于区块链技术搭建经济体系、社交体系、身份系统上密切融合,并且允许每个用户进行内容生产和世界编辑。这是清华大学给出的暂时定义,因为元宇宙仍是一个不断发展,演变的概念,不同的参与者仍在以自己的方式不断丰富着它的含义。

通俗来讲,想象你住在《动物森友会》里的一个岛上,每天打工做任务,并且出售自己设计的家具和服装,用挣来的钱叫了一份外卖,还买了一个虚拟艺人演唱会的票。在演唱会你认识了几个朋友,并相约在线下见面。这是不是有一种多元宇宙融合的感觉。

但元宇宙不等于是电子游戏也不是虚拟世界,元宇宙的公式是元宇宙等于虚拟世界乘以现实世界。扎克伯格强调“元宇宙”是一个长期产品,现在暂时还不存在。“你可以把元宇宙看作是一个具身性的互联网。在这里你不再浏览内容——而是在内容中。”扎克伯格说。

为什么需要元宇宙?

当前互联网产业的主要瓶颈是内卷化的平台形态。在内容载体、传播方式、交互方式、参与感和互动性上长期缺乏突破,导致“没有发展的增长”。元宇宙是打破桎梏,走出内卷的一个契机。

技术渴望新产品的出现,例如AI、XR、数字孪生、5G、大数据等对多种新型技术的统摄性想象。资本也一直都在寻找新出口,现实叠加虚拟打开广阔商业潜能。用户也一直期待着刺激的新体验,他们能够感受全新的交互体验从而摆脱“拇指党”。例如,可编辑开放世界,体感世界,真沉浸式社交,创造性游玩。还记得斯皮尔伯格2018年的电影《头号玩家》?这部“老”电影,就为我们展示了元宇宙的部分基础玩法。

Facebook早在2021年6月5日收购Unit2 Games,拥有了类似Roblox+Fortnite的元宇宙游戏平台《Crayta》。除了Facebook全世界入股元宇宙的公司还有Roblox、Epic Games,微软,字节跳动和腾讯。

现阶段,中国在元宇宙方面属于闷声干大事的阶段,能够看到腾讯,字节跳动和网易都先后在该领域有所涉猎,尤其是财大气粗的腾讯已经有了一套完善的元宇宙资本布局。

以腾讯为例,其元宇宙布局宏大,可无线缝合我们社交、生活、消费的各种平台,跨越了AR、VR、音频、互联网和物理世界。更重要的是,腾讯在其中每个环节,都具备了相当的竞争力,算得上是国内竞逐元宇宙企业中的全能型选手。

当然,入场元宇宙的正确通道是投资而并非完全拥有,对于本身就具备去中心化特征的元宇宙来说,把筹码分散在平台和内容创造者之间,而不是试图建立一个中央平台,是更合理的选择。

国内巨头们对元宇宙如此热衷,是可以理解的。仅从搜索热度来看,国人对次的热情和关注即可见一斑:4月18日,元宇宙相关关键词的搜索热度达到峰值,这可能这和4月13日Epic Games获得10亿美元投资和4月20日游戏引擎研发商代码乾坤(号称:中国版Roblox)获字节跳动近1亿人民币的战略投资有关;在10月末,由于Facebook更名事件,相关关键词的搜索量又被重新炒热。从世界范围来看,国内搜索引擎对于“元宇宙”的搜索量最高,也侧面证明了其在中国市场的无限潜力。

而元宇宙的竞争才刚刚开始,元宇宙的发展必然是一个长期的过程,从长远来看,元宇宙必将开启科技的新浪潮,开启一个全真互联网新时代。

元宇宙是一种互联网吗?它会取代互联网吗?

马克扎克伯格将元宇宙描述为“一个实体互联网”,基本上是互联网的升级版本,人们可以在其中拥有“在 2D 应用程序或网页上不一定能获得的不同体验”。

我们可以将元宇宙想象成“一种在线游乐场,用户可以和朋友一起玩像 Epic 的‘堡垒之夜’这样的多人游戏,然后通过 Netflix 观看电影。” 如果我们正在想象一个可以观看视频、与朋友一起玩游戏和购买东西的地方,那么它最终会看起来很像互联网。

元宇宙的关键承诺是“存在”。元宇宙的主要好处之一应该是“临场感”——一种你在身体上与地方和人物接触的感觉,而不是通过窗户观察他们。

如果你想看看一套衣服在你身上的样子,虚拟更衣室是有意义的。不过,它不一定需要整个虚拟商店,只是一种在平面和空间体验之间切换的简单方法。一个很好的比较点可能是移动互联网,它看到了大量基于应用程序的服务补充甚至取代了传统网站——但也没有让基于桌面的选项过时。所以,同样,元宇宙会是一个新的流量入口,但是不会取代互联网。

Go语言Web编程有哪些优势?

1.Go语言之前编程的痛点

(1)为什么会设计Go语言?

我们先来了解一下Go的作者和主要核心开发者们:Robert Griesemer, Rob Pike 和 Ken Thompson。设计Go语言是为了解决当时Google开发遇到的以下这些问题:

  • 大量的C++代码,同时又引入了Java和Python;
  • 成千上万的工程师;
  • 数以万计行的代码;
  • 分布式的编译系统;
  • 数百万的服务器;

其主要有以下几个方面的痛点:

  • 编译慢;
  • 失控的依赖;
  • 每个工程师只是用了一个语言里面的一部分;
  • 程序难以维护(可读性差、文档不清晰等);
  • 更新的花费越来越长;
  • 交叉编译困难;

所以,他们当时设计Go的目标是为了消除各种缓慢和笨重、改进各种低效和扩展性。Go是由那些开发大型系统的人设计的,同时也是为了这些人服务的;它是为了解决工程上的问题,不是为了研究语言设计;它还是为了让我们的编程变得更舒适和方便。

但是结合Google当时内部的一些现实情况,如很多工程师都是C系的,所以新设计的语言一定要易学习,最好是C-like的语言;因为有太多的分布式系统、太多的开发者,所以新的语言一定要可以Scale,这个包括开发、工程师、代码、部署和依赖;20年没有出新的语言了,所以新设计的语言必须是现代化的(例如内置GC)等情况,他们觉得要实现这个目标就需要Go成为一个大家都认可的语言。

最后根据实战经验,他们向着目标设计了Go这个语言,其主要的特色有:

  • 没有继承的OO;
  • 强一致类型;
  • Interface但是不需要显示申明(Duck Type);
  • Function 和Method;
  • 没有异常处理(Error is value);
  • 基于首字母的可访问特性;
  • 不用的Import或者变量引起编译错误;
  • 完整而卓越的标准库包;

Go发布之后,很多公司特别是云计算公司开始用Go重构他们的基础架构,很多都是直接采用Go进行了开发。这几年火到爆的Docker、Kubernetes就是采用Go开发的。我们来看看目前为止采用Go的一些国内外公司,国外的如Google、Docker、Apple、Cloud Foundry、CloudFlare、Couchbase、CoreOS、Dropbox、MongoDB、AWS等公司,国内的如阿里云CDN、百度、小米、七牛云、PingCAP、华为、金山软件、猎豹移动、饿了么等公司。

(2)Go主要应用的系统。

上面那些基本上就是Go的历史背景和设计初衷,那么目前Go主要应用于哪些系统呢?

目前Go主要应用在下面这些系统:

①Web服务器编程,以前你如果使用C或者C++做的那些事情,用Go来做很合适,例如处理日志、数据打包、虚拟机处理、文件系统等。

②容器开发:Docker,使开发高效且可预测;Kubernetes,也称为K8s,是一个开源系统,用于自动化容器化应用程序的部署,扩展和管理。

③微服务、分布式系统、数据库代理器等,例如gRPC、Etcd等。

④Web网络编程,这一块目前应用最广,包括Web应用、API应用、下载应用,而且Go内置的net/http包足够强大,基本就涵盖了常用的Web应用方法了。

⑤数据库,前一段时间Google开发的Groupcache,Couchbase的部分组建,Tidb,Cockroachdb,Influxdb等。

⑥云平台,目前国外很多云平台在采用Go开发,CloudFoundy的部分组建,前VMare的技术总监自己出来搞的Apcera云平台。

(3)为什么选择使用Go语言?

国内很多云创业公司都会选择把Go作为首要语言,例如七牛云等。为什么会选择Go呢?与其他语言的应用相比,它有什么优点呢?

①简单,学习曲线平稳;

它包含了类C语法、GC内置和工程工具。这一点非常重要,因为Go语言容易学习,所以一个普通的大学生花一个星期就能写出来可以上手的、高性能的应用。在国内大家都追求快,这也是为什么国内Go流行的原因之一。

②极致效率;

Go拥有接近C的运行效率和接近PHP的开发效率,这就很有利的支撑了上面大家追求快速的需求。

③Google公司开发;

之所以说Go出身名门,是因为我们知道Go语言出自Google公司,这个公司在业界的知名度和实力自然不用多说。Google公司聚集了一批牛人,在各种编程语言称雄争霸的局面下推出新的编程语言,自然有它的战略考虑。而且从Go语言的发展态势来看,Google对它这个新的宠儿还是很看重的,Go自然有一个良好的发展前途。我们看看Go语言的主要创造者,血统纯正这点就可见端倪了。

④自由高效:组合的思想、无侵入式的接口;

Go语言可以说是开发效率和运行效率二者的完美融合,天生的并发编程支持。Go语言支持当前所有的编程范式,包括过程式编程、面向对象编程以及函数式编程。程序员们可以各取所需、自由组合、想怎么玩就怎么玩。

⑤强大的标准库;

这包括互联网应用、系统编程和网络编程。Go里面的标准库基本上已经是非常稳定了,特别是我这里提到的三个,网络层、系统层的库非常实用。

⑥部署方便:二进制文件、Copy部署;

这一点是很多人选择Go的最大理由,因为部署太方便了,所以现在也有很多人用Go开发运维程序。

⑦简单而强大的并发处理能力;

它包含了降低心智的并发和简易的数据同步,我觉得这是Go最大的特色。之所以写正确的并发、容错和可扩展的程序如此之难,是因为我们用了错误的工具和错误的抽象,Go可以说这一块做的相当简单。

⑧规范,不会写出垃圾代码;

Go拥有强大的编译检查、严格的编码规范和完整的软件生命周期工具,具有很强的稳定性,稳定压倒一切。那么为什么Go相比于其他程序会更稳定呢?这是因为Go提供了软件生命周期(开发、测试、部署、维护等等)的各个环节的工具,如go tool、gofmt、go test等。

2.Go语言Web编程的优势

通过上面的介绍我们知道,Go语言Web开发领域有得天独厚的优势!Go语言被称为云计算时代的C语言。我们知道,在Web开发的世界里,敏捷才是王道。谁能使用更少的费用和资源来更快地完成网站和网络应用,谁就获得更多的竞争优势。此外,对于编程者而言,不仅希望快速完成Web开发,对可用性和用户体验的要求也很高。

这需要开发更多的功能和高级编程语言来开发网站功能,例如Go语言。本文着重介绍了Go语言 Web开发的好处,并将Go语言 Web编程与其他高度流行的语言进行了比较,例如 Python。

让我们看一下Python的特性,以及为什么它能够成为Web开发领域的主流。

(1)Python vs Go语言:优点与缺点

Python自20世纪80年代就出现了,但直到近些年它才变得流行。事实上,Python受欢迎程度已经连续6年增长,现在是最常用的编程语言之一。在Web开发中,它主要用于后端编程,但它也用于前端任务。最终,Python在Web开发场景中占优势的主要原因是它帮助开发人员解决敏捷性的迫切需求。它易于学习,简单易用,有助于快速完成复杂的目标。Python是灵活的,语法也很简单。

Go语言现在被认为是Python、Java等传统语言的替代品,关于Go语言 Web开发与Python、Java的讨论不胜枚举。

虽然简单是Python的主要优点,但也有一些缺点。许多开发人员发现,虽然对于一些简单和基本的开发Python很实用,但如果要构建更复杂的系统和定制模块,使用Python可能会变得很复杂。此外,经常出现令人沮丧的编码错误。在HekReNo.com文章中“从Python转到Go语言的五个原因”Tigran Bayburstyan说:“Python是一个伟大而有趣的语言,但有时你会遇到异常,因为你试图使用一个变量作为一个整数,但事实证明它是一个字符串。”Go会让你在编译时消除这些问题。

总而言之,在许多用例中,Go语言 Web开发已被证明比使用Python更快地完成同一类任务。最终,Go语言是为那些想要完成任务的人快速而有效地完成任务,而不需要进入编程语言的微妙之处。

(2)Python vs Go语言:哪一个更好?

那么,Go语言是否会在不久的将来取代Python呢?开发者社区正在讨论两种编程语言的优缺点。如果您正在寻找用于Web编程、移动开发、微服务和ERP系统的强大工具,我们相信,您应该切换到Go语言的原因是:

①简单性;

如果Python是迄今为止最容易学习的编程语言,那么Go语言甚至更简单。学习Go语言要比学习Python快得多。一些开发人员声称Go语言几乎和JavaScript一样简单。

②高级编译能力;

Go语言是一个编译执行语言,它能够直接将代码编译成可执行的二级制机器码。Go语言静态地将所有依赖库和模块编译到到一个二进制文件中。你不再需要在服务器上安装任何依赖项——你所需要做的就是上传一个编译的文件,你的应用就可以简单的运行了。

③并发和性能;

Go语言并发模型能够确保更高的性能(性能甚至 2x、3x的提升)。大多数现代编程语言都支持并发,但是Go语言采用了更节省资源的方法。相对于Python,Go语言提供更高性能的goroutine模型来支持多线程,goroutine能够更加节省CPU和内存资源。所以Go语言更有助于降低成本和资源。

④框架和库的本地支持;

Go语言 sdk包提供了功能丰富的API,因此不用过多的依赖第三方库就能很好的使用Go语言。当然,如果你需要的话,你可以下载很多工具和框架(Go语言周围的社区已经很强大很完善了),但是常用的API都已经内置到Go语言核心库中了。这样可以加快整个Go语言 Web开发过程的速度,并且使您无需寻找任何第三方依赖。

⑤顶级IDE和调试;

Go语言创作者在创建具有先进调试工具和插件的最先进的集成开发环境方面做得很好。这可以说是编程中最关键的方面,因为IDE会严重阻碍或加速开发过程。今天,当敏捷性给软件公司带来竞争优势时,伟大的IDE和调试工具是一个非常重要的优势。

⑥清晰的语法;

另一个有助于Go语言 Web编程出色的简单性和易用性的是其清晰的语法,它包含零不必要的组件。Go是建立在实用的头脑中的:而不是必须深入研究语言结构,开发者现在可以自由地专注于开发本身。

总结,通过上面的对比我们发现,Go语言在各方面基本都已经超过Python,尽管Python社区仍然超过Gophers,Go倡导者的数量每天都在增加,相信Go语言接近并超过Python、Java是大势所趋。

有了充分的理由,Go语言证明了“先进”不再等同于复杂、缓慢和昂贵。我们可以在不牺牲质量和大量投资的情况下实现显著的开发速度。此外,如果你决定使用Go,那么已经有许多Go语言网络框架供你选择。

3.Go语言Web开发常用框架

Go语言被称为云计算时代的C语言,它以其独特的优势逐渐被越来越多的公司所关注和使用。为了充分利用Go语言的Web开发优势,有必要熟悉一下Go语言的Web框架。

(1)Beego (http://beego.me/)

Beego是一个完全的MVC框架,你可以使用你的Go语言专业技术构建你的web应用程序。Beego 是用Go 语言开发的高效的 HTTP 框架,可以用来快速开发 API、Web应用及后端服务等各种应用。Beego是一个 RESTful 的框架,主要设计灵感来源于 tornado、sinatra 和 flask 这三个框架。它还结合了 Go语言自身的一些特性(接口、结构体嵌入等)。

1)Beego 架构简介。

Beego 是基于多个独立模块构建的,是一个高度解耦的框架。最初在设计 Beego 时就考虑到了功能模块化,用户即使不适用 Beego 的HTTP逻辑,也可以独立使用这些模块(例如可以使用cache模块来处理的缓存逻辑,使用日志模块来记录操作信息,使用config模块来解析各种格式的文件)。

Beego各模块的功能,以及使用方法会在接下来逐一介绍。

2)Beego 执行逻辑。

既然Beego 是基于模块构建的,那么它的执行逻辑是怎么样的呢?Beego 是一个典型的MVC框架,其执行逻辑如下图所示。

图1

执行逻辑可以拆分以下几段:

①main文件监听启动端口接收请求。

②请求经过路由和参数过滤功能被转发给绑定URL的控制器处理。

③控制器(Controller)调用辅助工具包、Model、Session管理、日志处理、缓存处理模块进行相应的业务处理。其中,模型(Model)通过ORM直接操作数据库。

④业务处理完成,返回响应或视图(View)给请求方。

(2)Gin(https://gin-gonic.github.io/gin/)

Gin是一个基于 Go 语言编写的 Web 框架。Gin框架拥有很好的性能,其借助高性能的httprouter,运行速度得到了极大提升。目前的 Gin 框架是1.x版本。

①安装。

下载并安装Gin:

$ go get -u github.com/gin-gonic/gin

②第一个Gin示例。

安装完成后,让我们开启Gin之旅。

package main

import (

    “github.com/gin-gonic/gin”

)

func main() {

    // 创建一个默认的路由引擎

    r := gin.Default()

    // GET:请求方式;/hello:请求的路径

    // 当客户端以GET方法请求/hello路径时,会执行后面的匿名函数

    r.GET(“/hello”, func(c *gin.Context) {

        // c.JSON:返回JSON格式的数据

        c.JSON(200, gin.H{

            “message”: “Hello world!”,

        })

    })

    // 启动HTTP服务,默认在0.0.0.0:8080启动服务

    r.Run()

}

运行以上代码,然后使用浏览器打开127.0.0.1:8080/hello即可看到一串JSON字符串。

(3)Revel(http://revel.github.io/)

Revel能让Go语言的web开发如虎添翼,大大提高你的开发效率。

(4)Martini (http://martini.codegangsta.io)

Martini是一个受到Sinatra (一个Ruby 框架)启发而开发的Go语言web框架。使用Martini,你可以快速写你的模块化应用或者服务。

(5)Traffic(https://github.com/pilu/traffic)

Traffic 同样也是受Sinatra的regexp/pattern 互斥思想启发下开发的web框架。它是一个小框架,并且是轻量型的。因此,它具有很好的灵活性,扩展性。

(6)Goji(https://goji.io/)

Goji是一个轻量型的web框架,具有简约性和灵活性的多路路由请求特性,正如它所标榜自己的那样。

4.Go语言Web编程书籍

(1)《Go Web编程实战派从入门到精通》廖显东 著 2021年4月出版

采用Go最新版本编写,拒绝纯理论,直接实战!实战!实战!重要的事说3遍!本书聚焦Go Web开发领域,对Go Web知识进行全面深入地讲解。货真价实高质量精品图书!本书有如下特色:

①一线技术,突出实战;

本书以实战为核心,贯穿整本书。所有代码采用Go最新版本编写。

②精雕细琢,阅读性强;

全书的语言经过多次打磨,力求精确。同时注重阅读体验,让没有任何基础的读者也可以很轻松的读懂书中的知识。

③零基础入门,循序渐进,实现快速从菜鸟向实战派高手迈进;

本书以Go入门级程序员为主要对象,初、中、高级程序员都可以从书中学到干货。先从Go的基础学起,然后学习Go核心的技术,再学Go的高级应用,然后再进行项目实战,最后介绍应用程序的Docker实战部署。全书从最基础的知识讲解一步一步到最核心的B2C电子商务系实战开发,真正帮助读者从基础入门向开发高手迈进。

④极客思维,极致效率;

本书以极客思维、深入Go语言底层进行探究,帮助读者了解背后原理。全书言简意赅,以帮助读者提升开发效率为导向,同时尽可能帮助读者缩短阅读本书的时间。

⑤由易到难,重难点标注并重点解析;

本书编排由易到难,内容基本覆盖Go Web的主流前沿技术。同时对重难点进行重点讲解,对易错点和注意点进行了提示说明,帮助读者克服学习过程中的困难。

⑥突出实战,快速突击;

本书的实例代码是绝大部分都是来自于最新的企业实战项目。对于购买本书的读者,所有的源代码均可以通过网上下载,直接下载即可运行,让读者通过实践来加深理解。

⑦实战方案,可直接二次开发进行实战部署;

本书全书以实战为主,所有的示例代码,拿来即可运行。特别是第9章,购买本书的读者可以直接获得B2C电子商务系统的全部源代码。可以直接作为电商项目进行二次开发,用于读者的项目。读者购买本书不仅可以学习本书的各种知识,也相当于购买一个最新版的Go语言电商系统解决方案及项目源码。

(2)《Go Web编程》【新加坡】郑兆雄 著 2017年12月出版

该书的优点:基础入门,出版较早。

该书的缺点:

①太过基础,并且没有循序渐进,需要一定Go语言基础。

②开发例子是国内已经过时的论坛系统,不符合当前市场需求。

③开发的部署是以Heroku、GoogleAppEngine、DigitalOcean等云平台上部署Go Web应用,不符合国内的具体情况。

④缺乏系统深入的知识体系。

⑤缺乏高级实战教程及国内大型架构经验的介绍,无法满足读者向高级迈进。

人工智能深度学习总结

人工智能实战主要由以下四部分组成:

  • 先从分工谈起
  • 深度学习基础概念
  • 深度学习进阶概念
  • 深度学习实战

先从分工谈起

机器学习工程师在公司中到底是一个怎样的存在?他的职责到底是什么?估计有不少开发者会有这样的疑惑。从机器学习的书中,从招工简章中,似乎都隐隐约约告诉大家:数学、算法……。然而,这个岗位中不是还有“工程师”三个字么?

image.png

先来看看机器学习工程师要构建的系统是什么样子:

image.png

诚如图中展示的,机器学习相关功能虽然是系统的核心,但它只是整个系统的一小部分,其他的功能(如安全权限、数据导入和处理、可视化等)并没有超出大多数普通开发者需要掌握的知识范畴。并且由上图,也很自然地导出了机器学习工程师需要掌握的知识技能:

从图中可以看出,“机器学习工程师”相当于“掌握了机器学习技能的工程师”:

  • 工程能力依旧是其首要掌握的技能,它需要利用这些技能在产品环境中实现模型:包括模型的训练和推理两个阶段。
  • 机器学习知识不可或缺。这一点毫无疑问,假如对机器学习一无所知,所谓的实现自然无从谈起。但就理论知识而言,并不要求他达到算法工程师或数据分析师那样的水准。两者的分工更多的是首先由后者在实验环境中把模型设计出来,然后再由机器学习工程师去实现即可。
  • 对于业务知识的理解同样也是必须。因为机器学习不是空中楼阁,它必须要解决实际问题。如果对问题域完全一抹黑,很难想象实际系统能工作得很好。这里很典型的一个例子就是对于输入数据的处理,要是缺乏业务问题的背景知识,可能连数据的含义都弄不明白,更不要说如何处理了。同样的,虽说机器学习工程师要求具备业务领域知识,但他不必成为领域专家,对于更深层次的问题,可以由后者提供专业帮助。

那么,作为普通工程师来讲,我们该如何开始去学习机器学习(或者说本文更关注的深度学习)呢?结合个人的学习过程,我建议将整个学习过程分为 3 个阶段。

阶段 1:找感觉

这一步是最难的。

假如你还没有被书中那些数学公式和推导过程吓到,仍然坚定地要入手专研机器学习,请给自己一个大大的 👍🏻!不过,在这个阶段,我建议不要把理论学习作为重点。相反地,我更建议大家先去找上一两个当前流行好用的机器学习框架,直接照着例子开始动手实验。这便是所谓的“找感觉”。

这个阶段的主要目的就是破除大多数开发者对于机器学习的神秘感和畏惧感,形成对机器学习的感性认识,进而找到自己的“感觉”。若是一开始就去专研机器学习理论,除非你天赋异禀,很容易陷入一大堆数学公式爬不出来,学了大半年却讲不清楚机器学习到底是什么,遇到实际问题也不知如何入手,其挫败感可想而知。

以上也是我自己的亲身体会。因此,为了避免上面的问题,我推荐大家一开始先不要去看理论背景很强的机器学习书籍,尤其是那些大学教材和算法类数据。而是先从一些实战类的书籍看起,以例子驱动的方式去学习。在形成对机器学习的感性认识之后,再去着手学习理论,以增强作为机器学习工程师的内涵。

同时,对于深度学习而言,为了更清楚地了解其背后的实现机理,不妨自己动手去实现一个简单地深度网络。

阶段 2:找队友

一个人学习总是孤单的,假如有同伴的话,情况就不一样了。不仅可以相互扶持和鼓励,也有助于形成一种竞争和合作的良好氛围。对于那些已经找到感觉的开发者,我建议可以去Kaggle找同好,顺便练练级,赚点外快(竞赛奖金)。作为国际知名的竞赛平台,Kaggle 的排名含金量非常高,并且还有什么比起在实战中提高能力更好的途径吗?

在练级的过程中,你很快就会发现自己的知识短板,此时,只需跟随你的感觉,缺啥补啥就好了。

一段时间之后,你已经具备了一定的理论知识和实战技巧。这时,不妨可以考虑将自己的所学和经验向社区(如自己的博客和 TFUG)输出,树立自己的个人品牌并检验自己的实际掌握程度。因为“你只能讲清楚你理解的东西”,假如你发现自己下笔困难或无法清晰地向他人讲清楚“机器学习是何物”,那么很可能是哪些地方还没有完全弄明白。

阶段 3:找方案

机器学习是门实践性很强的课程,不断有新的理论、方法和模型诞生。为了保持跟得上技术的发展,你还得去抽时间去搜集模型、论文和案例,好让这些能成为你未来武器库中的一部分。并且,作为开发者,为了更好地发挥你所用框架的潜力,对于框架的源码和机理需要做必要的了解,这样才有可能去进一步扩展和定制。

最后,在结束本节之前,我再来说说需要避免的学习误区:

  • 光看不练,这一点前面已经强调,不结合工具实战练习是无法掌握机器学习的。
  • 克服心理障碍,这一点非常重要。学习者千万不要被书中的数学公式吓到,随着技术的发展和时代的进步,一些平民化的工具已经出现了,典型如:Keras 和 TF。利用它们,实现一个深度网络并没有看上去的那么难。并且,参照上文所述,就机器学习工程师而言,数学的要求并不太高。
  • 神秘化 ML 类项目,这一类问题也同样需要避免。从前文可以看出,ML 项目就是用 ML 模型解决实际问题,与一般项目没有本质区别。
  • 模型自己写,这一点对于初学者来讲非常容易忽视。站在工程角度,预训练模型本质上就是类库,只要其解决的问题和我们当前正在解决的问题相当或相似,就可以考虑直接使用。
  • 不重视数据,这一点同样也是初学者容易忽视的问题。过于强调模型的重要性,这是初学者的通病,但倘若结合机器学习项目中的模型训练过程,就不难发现数据的重要性。假如把数据比做原材料,模型比做机器设备,很显然只有好数据才能得出好结果。

深度学习基础概念

在了解深度学习的基础概念之前,先来看看典型的机器学习分类:

  • 以解决问题的类型来分
    • 回归,预测连续值,如根据历史温度数据预测未来几天的温度值。
    • 分类,预测离散值,如 mnist 数据集的 0~9 的手写识别。
  • 以学习方式来分
    • 有监督学习,先通过标记好的数据集完成训练,然后使用训练好的模型完成预测。典型如上面手写识别和预测温度值的例子。
    • 无监督学习,训练数据没有标记,模型自行发现其中的关联。典型如聚类算法,输入一组数据,自动将数据完成分组。

讲深度学习,不能不提神经网络,而且既然有“深”自然就有“浅”,下图给出了两种网络的示意图,左边为“浅层”网络,右边为“深度”网络。

image.png

就大的结构而言,它们都由:输入层、隐藏层和输出层构成。所谓深浅之别,只不过在于:浅层网络的层数不会超过 3 层,反之则为深度网络。这个区分是不是有些意外地令人失望 😄?

根据神经网络理论,只需要输入输出两层全连接网络就可以“创造出世界”(只要不断加入神经元就好了,即胖网络),但为何又要引入“隐藏层”,并且后来又不断加深“隐藏层”的深度呢?原因就在于:

  • 计算的可行性。理论上虽然可行,但由于硬件的原因,两层神经网络不可能无限加宽,否则将导致整个计算无法进行。
  • 关联的灵活性。全连接可以视为暴力穷举的做法,而隐藏层则相当于对数据有一个二次加工的过程,利用不同的隐藏层结构和激活函数可以灵活地加工出所需的中间数据集,有助于改善数据之间的关联性。而层层递增的隐藏层其实就相当于数据不断精加工的过程,关联性一步步得到增强。

同时,“深”网络相比起“胖”网络,在计算上可以用现在的硬件得以实现。

了解完深度网络的概念,让我们再来看看深度网络的使用。整个使用过程分为两个阶段:

  • 训练阶段,这个阶段的目标就是得到一定网络模型下的权重矩阵和偏置矩阵。不妨将建模类比为“列方程组”,训练类比于“解方程组”的过程。
    1. 构建网络
    2. 训练数据数值化处理,即深度网络只能处理数值类型数据,对于文本、图像、音频等数据,需要借助一定的手段,将其转化成能被网络接受的数值表示。
    3. 前向传播计算偏差
    4. 后向传播调整权重和偏置
    5. 重复 3/4 直到偏差不再缩小
    6. 保存模型
  • 推理阶段
    1. 加载模型(网络 + 权重/偏置)
    2. 转化输入符合训练时的输入格式
    3. 调用模型预测结果
    4. 解释结果,深度网络预测的结果也是数值类型,对于这个类型的含义,应该由使用者来进行解释。

请注意,推理阶段的模型来源可以有两种:

  • 方式 1:自己造轮子。即自己建模型,自己训练,自己使用。
  • 方式 2:使用现成的预训练模型。还记得前面说的吗,模型本质上与类库没有什么区别,只要预训练模型要解决的问题和手头待解决问题属于一类问题,就可以考虑直接使用现成模型。

其中:

  • x 和 y 分别表示输入和输出。
  • W 和 b 分别表示网络的权重和偏置,也就是所谓的“知识”。
  • f 代表激活函数,它决定了神经元的输出,这也是为何它被称为“激活函数”的原因。
    • 如图所示,输出 Y = f((sum(x*w) + b),

然而,单个神经元并不能翻起多大风浪,必须将神经元按层组织,形成网络之后才有实际意义。对于网络中的层而言:

  • 层 = 一组神经元,可视为单个神经元的矩阵化
    • 输入(1 x m)、输出(1 x n)、W(m x n)、偏置(1 x n)
    • 输出 = 激活函数(输入 * 权重) + 偏置
  • 每个层可被视为数据的加工处理函数,其输出为中间数据集,并作为下一层的输入。
    • 层的组合形成了数据处理流水线,即网络结构。
  • 对于层的激活函数
    • 隐藏层常用:sigmod、relu、tanh 等
    • 输出层根据问题类型决定:
      • 回归问题(任意值),无
      • 回归问题(0~1),sigmod
      • 分类问题(n 选 1),softmax
      • 分类问题(2 选 1),sigmod

组建好了网络,自然需要对它进行训练。就训练过程而言,整个流程如下:

其中:

  • 损失函数,评判预测和实际的差距,不同类型的问题使用不同类型的损失函数,典型的有:
    • 回归问题:MSE
    • 分类问题:Cross Entropy
  • 优化器,调整权重和偏置,常见 SGD。

前面也说过,深度网络对于输入数据的要求是数值性,然而现实世界中的数据则不止于此,因此就必然涉及到对于输入数据预处理的问题。常见的预处理有:

  • 标准化和归一化
    • 避免量纲影响。比如有的输入量是 10000,有的又是 0.1,这样的数据直接进入网络训练往往效果不如人意。通过一定手段,将输入量统一到一个量纲之后,既简化了计算,同时也避免了量纲问题带来的训练效果不佳。
    • 简化计算
  • 缺失值
    • 众数(数据集中最常见的值)或均值
  • 字符标签
    • one-hot 编码,即有多少相异标签就引入多少个特征,处理时将相应特征对应的列标记为 1,如下图。可能有朋友会问,为什么不简单地用数字(如 1、2、3)来指代不同的分类呢?原因很简单:这样会带来隐含的关联关系。假设 red = 1,yellow = 2,这就隐含着 yellow > red,这显然是荒谬的。而采用 one-hot 编码则能有效避免这种问题。
  • 文本数据:先 token 化,再转换成数值向量。
  • 图像数据
    • 预处理,如灰度化
    • 动态生成图片,扩充数据集,如扭曲、颠倒等
  • 正则化,防止过拟合,关于过拟合的问题,参见下文。

此外,关于训练,你还需要了解下面的常见术语,有时候你会在一些书籍和代码中看到它们:

  • 1 pass,一条数据处理完毕
  • 1 iteration,一批样本数据中所有数据处理完毕
  • 1 epoch,所有批次所有样本数据处理完毕

同时,在训练模型时,你需要考虑:

  • batch 大小,它决定了权重更新时机,越小,则更新越频繁
  • epoch 大小,它决定了训练次数,随着一轮一轮的训练,你会发现预测的差异在不断变小。最后,每一 epoch 之间差异改善并不大,这时就可以考虑停止训练了。

在实际过程中,常常将训练数据集划分为 3 部分:

  • 训练集,训练数据
  • 验证集,训练过程中验证训练效果没有下降
  • 测试集,训练完毕后检验训练效果

验证集存在的价值在于提早发现问题,终止无用的训练。因为训练本身是一个耗时耗力的过程,若训练了半天发现效果很差,那么还不如提早结束。利用验证集,可以很早就发现过拟合现象。

这三类数据集的比例通常如下(训练集、验证集、测试集):

  • 60:20:20
  • 70:10:20
  • 超大数据集:95:2:3

为了最大化利用这些来之不易的数据的价值,在实际部署之前,往往会将整个训练数据集合为一体,输入模型,完成对模型上线前的最终训练。

在本节最后,看看深度模型的部署方式。还记得吗,在本文中一直强调“模型即类库”。那么在部署方式上,其实也非常类似:

  • 方式 1:API。如:Rest 框架 + 模型
  • 方式 2:嵌入应用。如:MVC 框架 + 模型

在实际过程中需要注意:

  • 输入数据需符合模型预期
  • 模型输出需应用自己解释。这一点很显然,因为模型的输出是一个数值类型,对于它的具体含义解释必然是跟应用相关的。
  • 训练和使用可以是不同框架,如在 DL4J 环境中使用 TF 训练的模型

深度学习进阶概念

上一节中提到,将层视为不同的数据处理器,不同类型的层完成不同类型的工作。Keras 框架中典型的层有:

  • Convolution,抽取局部特征
  • Pooling,跟 Convolution 配合使用,典型 MaxPooling、AvgPooling 等
  • DropOut,随机去掉一定比例神经元
  • Dense,全连接
  • Embedding,词向量转换
  • Recurrent,处理序列数据,如文本和时序
  • Merge,合并多个输入层数据

因此,构建网络的过程就是使用不同层进行组合的过程,本质上等同于使用编程语句构建程序。同时需要注意,一般情况下,输出层都为 Dense。这里可以理解为,通过隐藏层不断加强数据的关联性和缩小范围之后,最终通过暴力穷举解决问题。

前文已经出现了“过拟合”一词,现在我们来讨论一下关于拟合的两个概念:欠拟合和过拟合。

  • 欠拟合,可视为网络学习能力低下,无法从训练数据学到任何东西。导致它出现的典型原因主要是网络结构存在缺陷,比如“小网络,大数据”。修复它的办法也很直接,改进网络,比如:
    • 增加每层神经元
    • 增加网络层级
  • 过拟合,可类比于“死记硬背”,对训练数据几乎能达到 100%,对测试数据,则表现不如人意。典型原因“大网络、小数据”。主要的改进对策:
    • 数据正则化:L1 和 L2,本质上是通过对成本函数引入惩罚机制来限制网络的自由度。
    • DropOut,在训练过程中随机丢弃层中一定比例的神经元,不让它们参与计算。

如果将网络类比为“内存”就很容易理解上面的两个概念。前一种相当于内存不足以容纳全部数据,从而无法学习;后者则相当于内存远超数据量,导致对现有数据通过死记硬背的方式就能蒙混过关。一般在实际工作中,欠拟合很容易发现,因此这里也不做过多强调。过拟合,则是从业者经常与之斗争的“顽疾”。这也是为何要引入“验证集”,提前发现过拟合现象,及时终止训练,避免浪费时间。

另一个需要了解的进阶概念就是“鞍点”,有一定高数背景的读者应该对于通过“求导求极值”的做法并不陌生,深度学习中的优化方法本质上仍是如此。由上图可见,在鞍点附近,导数(斜率)几乎为 0。这样造成的负面后果就是:

  • 学习性能低下,迟迟无法收敛
  • 无法获得理想结果,这里只是得到了局部的优化值,因此鞍点本身又有“局部极值”的叫法。

为了应对这种情况,一般采用:

  • 使用有动量的优化算法,如 Adagrad、RMSProp。套用一般深度学习书中将优化过程比喻成“小球”沿梯度方向滚动的说法,所谓动量可视为让小球具有一定的加速度,快速通过鞍点的过程。
  • 自适应学习率,因为学习率决定了权重调整的大小

最后一个需要掌握的进阶概念就是“超参数”,它本质上相当于模型的“元数据”,无法通过训练过程得到。典型的超参数有:

  • 神经元个数
  • 网络层数
  • 激活函数
  • 优化器
  • 学习率
  • Epoch 数
  • Batch 大小

并且超参数的调优过程是一个不断实验的体力活,一般的做法有:人工、Grid Search、随机优化、贝叶斯优化。随着技术的发展,目前也有类似 AutoML 的的端到端解决方案出现,相信未来会更美好。

深度学习实战

关于深度学习用到的框架和工具,以及实验环境的搭建,如下代码大家可以对于使用 Keras 编写深度网络有一个感性认识:

from keras import layers
from keras import models

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

总结

讲到这里,我希望这次分享能够消除大家对于深度学习的神秘感和恐慌,真正动手去做做练习,在实践中成长。最后总结一下:

  • 深度学习入门并没有想象中那么困难
  • 借助 Keras 等工具可以快速实现网络模型
  • 可以看出,深度网络的调参是个脏活累活。但 AutoML 和 AutoKeras 这类工具的出现,意味着自动调参时代即将到来。
  • 建议学习方法:Make Your Hands Dirty

参考

Go语言 同步sync包简介

Sync包简介

1. 什么是Sync包?

Package sync provides basic synchronization primitives such as mutual exclusion locks. Other than the Once and WaitGroup types, most are intended for use by low-level library routines. Higher-level synchronization is better done via channels and communication.

Values containing the types defined in this package should not be copied.

这句话大意是说:
Sync包同步提供基本的同步原语,如互斥锁。 除了Once和WaitGroup类型之外,大多数类型都是供低级库例程使用的。 通过Channel和沟通可以更好地完成更高级别的同步。并且此包中的值在使用过后不要拷贝。

从描述中可以看到的是,Go语言并不推荐这个包中的大多数并发控制方法,但还是提供了相关方法,主要原因是Go语言中提倡以共享内存的方式来通信:

不要以共享内存的方式来通信,作为替代,我们应该以通信的手段来共享内存

共享内存的方式使得多线程中的通信变得简单,但是在并发的安全性控制上将变得异常繁琐。
正确性不是我们唯一想要的,我们想要的还有系统的可伸缩性,以及可理解性,我觉得这点非常重要,比如现在广泛使用的Raft算法。

2. 包中的Type

包中主要有: Locker, Cond, Map, Mutex, Once, Pool,
RWMutex, WaitGroup

type Locker interface {
        Lock()
        Unlock()
}
type Cond struct {
        // L is held while observing or changing the condition
        L Locker
}

3. 什么是锁,为什么需要锁?

锁是sync包中的核心,他主要有两个方法,加锁和解锁。
在单线程运行的时候程序是顺序执行的,程序对数据的访问也是:
读取 => 一顿操作(加减乘除之类的) => 写回原地址
但是一旦程序中进行了并发编程,也就是说,某一个函数可能同时被不同的线程执行的时候,以时间为维度会发生以下情况:

可以看到的是,A地址的数字被执行了两次自增,若A=5,我们在执行完成后预期的A值是7,但是在这种情况下我们得到的A却是6,bug了~
还有很多类似的并发错误,所以才有锁的引入。若是我们在线程2读取A的值的时候对A进行加锁,让线程2等待,线程1执行完成之后在执行线程2,这样就能够保证数据的正确性。但是正确性不是我们唯一想要的。

4.写更优雅的代码

在很多语言中我们经常为了保证数据安全正确,会在并发的时候对数据加锁

Lock()
doSomething()
Unlock()

Go语言在此包中也提供了相关的锁,但是标明了”most are intended for use by low-level library routines” 所以我这里只对 Once and WaitGroup types做简述。

5.Once 对象

Once 是一个可以被多次调用但是只执行一次,若每次调用Do时传入参数f不同,但是只有第一个才会被执行。

func (o *Once) Do(f func())


    var once sync.Once
    onceBody := func() {
        fmt.Println("Only once")
    }
    done := make(chan bool)
    for i := 0; i < 10; i++ {
        go func() {
            once.Do(onceBody)
            done <- true
        }()
    }
    for i := 0; i < 10; i++ {
        <-done
    }

如果你执行这段代码会发现,虽然调用了10次,但是只执行了1次。BTW:这个东西可以用来写单例。

6. WaitGroup

func (wg *WaitGroup) Add(delta int)
func (wg *WaitGroup) Done()
func (wg *WaitGroup) Wait()

wait group 用来等待一组goroutines的结束,在主Goroutine里声明,并且设置要等待的goroutine的个数,每个goroutine执行完成之后调用 Done,最后在主Goroutines 里Wait即可。下面是个官方的例子:

var wg sync.WaitGroup
var urls = []string{
        "http://www.golang.org/",
        "http://www.google.com/",
        "http://www.somestupidname.com/",
}
for _, url := range urls {
        // Increment the WaitGroup counter.
        wg.Add(1)
        // Launch a goroutine to fetch the URL.
        go func(url string) {
                // Decrement the counter when the goroutine completes.
                defer wg.Done()
                // Fetch the URL.
                http.Get(url)
        }(url)
}
// Wait for all HTTP fetches to complete.
wg.Wait()

7. 总结

Go语言中高级的并发可以通过channel来实现,这是Go语言所倡导的,但是Go语言也提供了锁等先关操作。

恭喜老詹,35岁的詹姆斯,依旧狂奔在追逐乔丹的路上!


在去年7月,这支湖人刚刚组建完成时,有几个人愿意相信他们能够成功地走到最后呢?在那些质疑者的眼里,这是一支危机四伏,随时都有可能被推翻重来的球队。
他们认为湖人的管理团队太过混乱,缺少成为一支伟大球队所需要的稳定性。
他们虽然认可球队的教练组豪华万分,但却认为由三名前任NBA主帅搭建起来的核心构架,更有可能发生的是暗流涌动,各自心怀鬼胎。
他们认为湖人的阵容缺乏深度,虽有詹眉打底,但却没有稳定可靠的第三点,远不及其他的竞争对手。
他们认为詹姆斯老了,即将年满35周岁的他,很有可能再次被伤病给盯上,一个无法全力输出的詹姆斯,必定无法统帅一支成功的球队。
但,他们错了。
在走完了这段长达一年多的漫长旅途后,洛杉矶湖人,时隔十年再度踏上了世界之巅。至少在这个夜晚,那些质疑者们可以闭嘴了。
湖人这一次的成功,属于队里的每一个人。

他们低估了湖人的教练组。
事后来看,这是一个出色的团队,初期的试探,赛间的调整,甚至有魄力在赛中对阵容的搭配进行临时的修整。他们的准备之充分,应对手法之深厚,显然超过了外界最初的预期。
他们低估了湖人的角色球员与年轻人,能在一年的时间里所收获的成长。
这些失意的,不被人看好的,无人问津的球员,在洛杉矶重新收获了信任,他们打出了强硬的防守表现,留下了无数闪耀的瞬间。

他们低估了安东尼-戴维斯的价值。
在来到这之前,他是众人嘴中调侃的“美国之子”,现役最著名的“荣誉摇摆人”,名大于实的代表人物。
但在来到这之后,他用行动证明了自己的价值,证明了为什么他是这个时代最好最全能的内线球员。他不仅构建起了球队的防守体系,更是他们在进攻端最锋利的刺刃,因为浓眉的存在,让洛杉矶人拥有了更多破解防守与应对进攻的办法,他是球队能够登顶的重要功臣与关键之一。

当然,被他们所低估的,还有勒布朗-詹姆斯的领导力与决心。
的确,他35岁了,跑的没有以前那么快了,跳的没有年轻时那么高了,身体也会受到一些伤病的困扰了,可他追逐伟大的心,依旧炽热。
“我努力奋斗的所有动力,都是为了追逐那个曾经在芝加哥打球的幽灵。”
4年前,刚刚率领着克利夫兰骑士打破52年魔咒,逆天登顶的勒布朗,在接受时任《体育画报》记者的詹金斯采访时,说出了这句话。而在时隔4年之后今天,他依旧在用行动践行着自己曾经许下的诺言。
每当詹姆斯赢得一次总冠军,关于他能否超越乔丹这个议题,就会重新开始被人热议。对此,我也听过不少的“狠话”,总结着来讲,大概意思就是:“从从前,到现在,乃至将来,‘乔丹是至高无上的篮球之神’这件事,永远都不会发生改变。”
我当然也跟大多数人一样,非常认同乔丹在篮球世界里如象征图腾一般的地位。他所取得的荣誉是无上的,他所做到过的那些事情是极富传奇色彩的,他配得上任何人为他送上的任何赞美,哪怕距离他完全退役已过去近20年之久,迈克尔-乔丹这个名字也依旧还在影响着这项运动,正如我们每个人在最初遇见篮球时所知道的第一个名字,永远属于他一样。
但是,仅就我个人而言,我并不相信所谓“真理的永恒”。
乔丹之所以被称为篮球之神,绝非靠的一手虚无的赞美,而是因为那一连串的数字实在太过耀眼——10届得分王,3届抢断王,1个DPOY,5个MVP,6次夺得总冠军,6次拿下FMVP,10个年度一阵,9个年度一防,外加一票多到数不清,哪哪都有他的数据纪录——他的伟大,无需吹捧,也经得起任何比较。
但这并不意味着,当这些数字开始受到别人挑战时,他依旧能靠着所谓“神性”,永远高枕无忧地坐在那个位子上。
虽然詹姆斯目前还不足以威胁到乔丹,但显然,他已经拉近了自己与少年偶像的距离。只是偏见与固有看法的存在,让人或多或少地低估了眼前人所创造的那些传奇成就。

比如有的人会用总决赛胜率来贬低詹姆斯。
的确,40%的总决赛胜率在“乔丹不打第七场”和“乔丹从未输过总决赛”面前,显得有些脆弱不堪。
但又有多少人忽略了,那可是长达10年的总决赛征战啊,更何况我们在评判一件事物的好与坏时,真的该用如此一刀切的方式么?
2007年,四年级的新星勒布朗-詹姆斯独自率领着克利夫兰骑士,史无前例地杀进了总决赛,然后败给了无论阵容,或是核心都要更加强大且老辣的圣安东尼奥马刺,这样的失败,难道不该被加上引号么;
2015年,乐福与欧文相继倒下,詹姆斯带着82万年薪的先发控卫,总价不过2120万美元的核心6人组,与勇士厮杀了6场最终抱憾收场的失败,也应该受人唾弃么;
2018年,欧文出走,球队中期地震式动荡,在经历了两轮大清洗之后,不仅丢掉了明星实力,也彻底失去了自己的阵容深度。整个季后赛,除詹姆斯能每场稳定贡献34分之外,仅乐福一人场均得分上双(14.9分),且命中率只有惨淡的39.2%。但就是在这种极端的情况下,他依旧扛着骑士踏上了总决赛的舞台。的确,在强悍的勇士面前,他一场都没赢,可单场51分拼到加时的神勇,你真的会觉得这是一种耻辱么?
我永远不会这么认为,我只会觉得这是詹姆斯将一支本不属于总决赛的球队,带到了那个位置上,我更愿意将其视作是个人的一次巨大成功。

再比如,有人认为詹姆斯的数据积累之所以如此骇人,纯粹只是因为他打的比较多而已。
但近在眼前的例子——金州勇士核心成员的遭遇——告诉我们:长时间高强度的征战,所能带来的东西绝非只有数据与荣誉,更有身体上的超负荷运转。
17年的职业生涯,有超过一半的时间,詹姆斯都打进了总决赛,他在季后赛的出场时间超过了1万分钟,排名NBA历史第一,几乎是现役排行老二的凯文-杜兰特的一倍之多。
他能够扛住如此长时间的高强度对抗,除了得益于他惊人的身体天赋之外,更重要的,是数年如一日的努力,是对饮食与生活的严苛管理,以及对自身身体的精心照料。
我们早已习惯了他展现在世人面前的优秀,却总是会忽略掉掩藏在这一切背后的血与泪。
打的比赛多,是努力付出之后的回报,更是能力的体现。这本该受到褒奖,但在詹姆斯身上,却无奈地成了另一种被人看低的方式。
这一切,真的就本该如此么?

我不想说詹姆斯未来必定还能取得怎样的荣誉,或是数据积累。毕竟谁都无法确定没有发生过的事。但在今天,在詹姆斯拿下自己职业生涯第4个总冠军和第4座总决赛MVP的奖杯后,他已经成为了NBA历史上仅次于迈克尔-乔丹的球员——在这之前,除了乔丹,没人拿到过超过3个FMVP——他理应获得足够的尊重。
就像他在捧起奖杯时说的那番话一样:“我想得到的,是尊重。”
在他出现在这之前,我们甚至没有见过一个哪怕能够接近乔丹的人,而在这之后,我们也无从确认,下一个拥有这等能力的天才,会在何年何月再次降临。
第17个赛季落幕,年近36岁的詹姆斯,依旧狂奔在这条追赶伟大幽灵的路上。他或许可以成功,又或许不能。但我想,当你有机会去见证这样一段跨越历史的较量时,期待与祝福,终归是要强过诋毁与谩骂的。
在这样一个时刻,在所有人在高呼着“湖人总冠军”的时候,我更想把我的心里话,送给这个时代最伟大的篮球运动员:
“恭喜你,勒布朗-詹姆斯,在经历了17年的漫长旅途之后,你终于获得了挑战神的资格。这个画面,是自你踏入联盟的第一天起,就被世人所寄予的期待。就现在,抬起头看看,上帝的神像就矗立在那座山峰之上,你能看见他,他不远了,去挑战他吧!”

kubectl 技巧总结

Kubectl 是 Kubernetes 最重要的命令行工具。在 Flant,我们会在 Wiki 和 Slack 上相互分享 Kubectl 的妙用(其实我们还有个搜索引擎,不过那就是另外一回事了)。多年以来,我们在 kubectl 方面积累了很多技巧,现在想要将其中的部分分享给社区。

我相信很多读者对这些命令都非常熟悉;然而我还是希望读者能够从本文中有所获益,进而提高生产力。

下列内容有的是来自我们的工程师,还有的是来自互联网。我们对后者也进行了测试,并且确认其有效性。

现在开始吧。

获取 Pod 和节点

  1. 我猜你知道如何获取 Kubernetes 集群中所有 Namespace 的 Pod——使用 --all-namepsaces 就可以。然而不少朋友还不知道,现在这一开关还有了 -A 的缩写。
  2. 如何查找非 running 状态的 Pod 呢? kubectl get pods -A --field-selector=status.phase!=Running | grep -v Complete顺便一说,--field-selector 是个值得深入一点的参数。
  3. 如何获取节点列表及其内存容量: kubectl get no -o json | \
    jq -r '.items | sort_by(.status.capacity.memory)[]|[.metadata.name,.status.capacity.memory]| @tsv'
  4. 获取节点列表,其中包含运行在每个节点上的 Pod 数量: kubectl get po -o json --all-namespaces | \
    jq '.items | group_by(.spec.nodeName) | map({"nodeName": .[0].spec.nodeName, "count": length}) | sort_by(.count)'
  5. 有时候 DaemonSet 因为某种原因没能在某个节点上启动。手动搜索会有点麻烦: $ ns=my-namespace
    $ pod_template=my-pod
    $ kubectl get node | grep -v \"$(kubectl -n ${ns} get pod --all-namespaces -o wide | fgrep ${pod_template} | awk '{print $8}' | xargs -n 1 echo -n "\|" | sed 's/[[:space:]]*//g')\"
  6. 使用 kubectl top 获取 Pod 列表并根据其消耗的 CPU 或 内存进行排序: # cpu
    $ kubectl top pods -A | sort --reverse --key 3 --numeric
    # memory
    $ kubectl top pods -A | sort --reverse --key 4 --numeric
  7. 获取 Pod 列表,并根据重启次数进行排序:kubectl get pods —sort-by=.status.containerStatuses[0].restartCount当然也可以使用 PodStatus 以及 ContainerStatus 的其它字段进行排序。

获取其它数据

  1. 运行 Ingress 时,经常要获取 Service 对象的 selector 字段,用来查找 Pod。过去要打开 Service 的清单才能完成这个任务,现在使用 -o wide 参数也可以: $ kubectl -n jaeger get svc -o wide
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
    jaeger-cassandra ClusterIP None <none> 9042/TCP 77d app=cassandracluster,cassandracluster=jaeger-cassandra,cluster=jaeger-cassandra
  2. 如何输出 Pod 的 requests 和 limits $ kubectl get pods -A -o=custom-columns='NAME:spec.containers[*].name,MEMREQ:spec.containers[*].resources.requests.memory,MEMLIM:spec.containers[*].resources.limits.memory,CPUREQ:spec.containers[*].resources.requests.cpu,CPULIM:spec.containers[*].resources.limits.cpu'
    NAME MEMREQ MEMLIM CPUREQ CPULIM
    coredns 70Mi 170Mi 100m <none>
    coredns 70Mi 170Mi 100m <none>
    ...
  3. kubectl run(以及 createapplypatch)命令有个厉害的参数 --dry-run,该参数让用户无需真正操作集群就能观察集群的行为,如果配合 -o yaml,就能输出命令对应的 YAML: $ kubectl run test --image=grafana/grafana --dry-run -o yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    creationTimestamp: null
    labels:
    run: test
    name: test
    spec:
    replicas: 1
    selector:
    matchLabels:
    run: test
    简单的把输出内容保存到文件,删除无用字段就可以使用了。1.18 开始 kubectl run 生成的是 Pod 而非 Deployment。
  4. 获取指定资源的描述清单: kubectl explain hpa
    KIND: HorizontalPodAutoscaler
    VERSION: autoscaling/v1
    DESCRIPTION:
    configuration of a horizontal pod autoscaler.
    FIELDS:
    apiVersion <string>
    ...

网络

  1. 获取集群节点的内部 IP: $ kubectl get nodes -o json | jq -r '.items[].status.addresses[]? | select (.type == "InternalIP") | .address' | \
    paste -sd "\n" -
    9.134.14.252
  2. 获取所有的 Service 对象以及其 nodePort $ kubectl get -A svc -o json | jq -r '.items[] | [.metadata.name,([.spec.ports[].nodePort | tostring ] | join("|"))]| @tsv'

    kubernetes null
    ...
  3. 在排除 CNI(例如 Flannel)故障的时候,经常会需要检查路由来识别故障 Pod。Pod 子网在这里非常有用: $ kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}' | tr " " "\n" fix-doc-azure-container-registry-config ✭
    10.120.0.0/24
    10.120.1.0/24
    10.120.2.0/24

日志

  1. 使用可读的时间格式输出日志: $ kubectl logs -f fluentbit-gke-qq9w9 -c fluentbit --timestamps
    2020-09-10T13:10:49.822321364Z Fluent Bit v1.3.11
    2020-09-10T13:10:49.822373900Z Copyright (C) Treasure Data
    2020-09-10T13:10:49.822379743Z
    2020-09-10T13:10:49.822383264Z [2020/09/10 13:10:49] [ info] Configuration:
  2. 只输出尾部日志: kubectl logs -f fluentbit-gke-qq9w9 -c fluentbit --tail=10
    [2020/09/10 13:10:49] [ info] ___________
    [2020/09/10 13:10:49] [ info] filters:
    [2020/09/10 13:10:49] [ info] parser.0
    ...
  3. 输出一个 Pod 中所有容器的日志:kubectl -n my-namespace logs -f my-pod —all-containers
  4. 使用标签选择器输出多个 Pod 的日志:kubectl -n my-namespace logs -f -l app=nginx
  5. 获取“前一个”容器的日志(例如崩溃的情况):kubectl -n my-namespace logs my-pod —previous

其它

  1. 把 Secret 复制到其它命名空间: kubectl get secrets -o json --namespace namespace-old | \
    jq '.items[].metadata.namespace = "namespace-new"' | \
    kubectl create-f -
  2. 下面两个命令可以生成一个用于测试的自签发证书: openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=grafana.mysite.ru/O=MyOrganization"
    kubectl -n myapp create secret tls selfsecret --key tls.key --cert tls.crt

相关链接

本文没什么结论,但是可以提供一个小列表,其中包含本文相关的有用链接。

  1. Kubernetes 官方文档:https://kubernetes.io/docs/reference/kubectl/cheatsheet/
  2. Linux Academy 的入门参考:https://linuxacademy.com/blog/containers/kubernetes-cheat-sheet/
  3. Blue Matador 分类整理的命令列表:https://www.bluematador.com/learn/kubectl-cheatsheet
  4. 另一个命令指南,部分内容和本文重复:https://gist.github.com/pydevops/0efd399befd960b5eb18d40adb68ef83
  5. kubectl 别名搜集:https://github.com/ahmetb/kubectl-aliases