教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 兄弟连golang神技(1)-关于 Go 语言的介绍

兄弟连golang神技(1)-关于 Go 语言的介绍

发布时间:2021-12-27   编辑:jiaochengji.com
教程集为您提供兄弟连golang神技(1)-关于 Go 语言的介绍等资源,欢迎您收藏本站,我们将为您提供最新的兄弟连golang神技(1)-关于 Go 语言的介绍资源
计算机一直在演化,但是编程语言并没有以同样的速度演化。现在的手机,内置的 CPU 核
数可能都多于我们使用的第一台电脑。高性能服务器拥有 64 核、128 核,甚至更多核。但是我
们依旧在使用为单核设计的技术在编程。
编程的技术同样在演化。大部分程序不再由单个开发者来完成,而是由处于不同时区、不同
时间段工作的一组人来完成。大项目被分解为小项目,指派给不同的程序员,程序员开发完成后,
再以可以在各个应用程序中交叉使用的库或者包的形式,提交给整个团队。
如今的程序员和公司比以往更加信任开源软件的力量。Go 语言是一种让代码分享更容易的编
程语言。Go 语言自带一些工具,让使用别人写的包更容易,并且 Go 语言也让分享自己写的包
更容易。
在本章中读者会看到 Go 语言区别于其他编程语言的地方。Go 语言对传统的面向对象开发
进行了重新思考,并且提供了更高效的复用代码的手段。Go 语言还让用户能更高效地利用昂贵
服务器上的所有核心,而且它编译大型项目的速度也很快。
在阅读本章时,读者会对影响 Go 语言形态的很多决定有一些认识,从它的并发模型到快如
闪电的编译器。我们在前言中提到过,这里再强调一次:这本书是写给已经有一定其他编程语言
经验、想学习 Go 语言的中级开发者的。本书会提供一个专注、全面且符合习惯的视角。我们同
时专注语言的规范和实现,涉及的内容包括语法、Go 语言的类型系统、并发、通道、测试以及
其他一些非常广泛的主题。我们相信,对刚开始要学习 Go 语言和想要深入了解语言内部实现的
人来说,本书都是最佳选择。
本书示例中的源代码可以在 https://github.com/goinaction/code 下载。
我们希望读者能认识到,Go 语言附带的工具可以让开发人员的生活变得更简单。最后,读
者会意识到为什么那么多开发人员用 Go 语言来构建自己的新项目。
1
第 1 章 关于 Go 语言的介绍
1.1 用 Go 解决现代编程难题
Go 语言开发团队花了很长时间来解决当今软件开发人员面对的问题。开发人员在为项目选
择语言时,不得不在快速开发和性能之间做出选择。C 和 C 这类语言提供了很快的执行速度,
而 Ruby 和 Python 这类语言则擅长快速开发。Go 语言在这两者间架起了桥梁,不仅提供了高性

能的语言,同时也让开发更快速。


在探索 Go 语言的过程中,读者会看到精心设计的特性以及简洁的语法。作为一门语言,Go
不仅定义了能做什么,还定义了不能做什么。Go 语言的语法简洁到只有几个关键字,便于记忆。
Go 语言的编译器速度非常快,有时甚至会让人感觉不到在编译。所以,Go 开发者能显著减少等
待项目构建的时间。因为 Go 语言内置并发机制,所以不用被迫使用特定的线程库,就能让软件
扩展,使用更多的资源。Go 语言的类型系统简单且高效,不需要为面向对象开发付出额外的心
智,让开发者能专注于代码复用。Go 语言还自带垃圾回收器,不需要用户自己管理内存。让我
们快速浏览一下这些关键特性。
1.1.1 开发速度
编译一个大型的 C 或者 C 项目所花费的时间甚至比去喝杯咖啡的时间还长。图 1-1 是 XKCD
中的一幅漫画,描述了在办公室里开小差的经典借口。
图 1-1 努力工作?(来自 XKCD)
Go 语言使用了更加智能的编译器,并简化了解决依赖的算法,最终提供了更快的编译速度。
编译 Go 程序时,编译器只会关注那些直接被引用的库,而不是像 Java、C 和 C 那样,要遍历
依赖链中所有依赖的库。因此,很多 Go 程序可以在 1 秒内编译完。在现代硬件上,编译整个 Go
语言的源码树只需要 20 秒。
因为没有从编译代码到执行代码的中间过程,用动态语言编写应用程序可以快速看到输出。
代价是,动态语言不提供静态语言提供的类型安全特性,不得不经常用大量的测试套件来避免在
运行的时候出现类型错误这类 bug。
想象一下,使用类似 JavaScript 这种动态语言开发一个大型应用程序,有一个函数期望接收
一个叫作 ID 的字段。这个参数应该是整数,是字符串,还是一个 UUID?要想知道答案,只能
去看源代码。可以尝试使用一个数字或者字符串来执行这个函数,看看会发生什么。在 Go 语言
里,完全不用为这件事情操心,因为编译器就能帮用户捕获这种类型错误。
1.1.2 并发
作为程序员,要开发出能充分利用硬件资源的应用程序是一件很难的事情。现代计算机都拥
有多个核,但是大部分编程语言都没有有效的工具让程序可以轻易利用这些资源。这些语言需要
写大量的线程同步代码来利用多个核,很容易导致错误。
Go 语言对并发的支持是这门语言最重要的特性之一。goroutine 很像线程,但是它占用的
内存远少于线程,使用它需要的代码更少。通道(channel)是一种内置的数据结构,可以让
用户在不同的 goroutine 之间同步发送具有类型的消息。这让编程模型更倾向于在 goroutine
之间发送消息,而不是让多个 goroutine 争夺同一个数据的使用权。让我们看看这些特性的

细节。


1.goroutine
goroutine 是可以与其他 goroutine 并行执行的函数,同时也会与主程序(程序的入口)并行
执行。在其他编程语言中,你需要用线程来完成同样的事情,而在 Go 语言中会使用同一个线程
来执行多个 goroutine。例如,用户在写一个 Web 服务器,希望同时处理不同的 Web 请求,如果
使用 C 或者 Java,不得不写大量的额外代码来使用线程。在 Go 语言中,net/http 库直接使用了
内置的 goroutine。每个接收到的请求都自动在其自己的 goroutine 里处理。goroutine 使用的内存
比线程更少,Go 语言运行时会自动在配置的一组逻辑处理器上调度执行 goroutine。每个逻辑处
理器绑定到一个操作系统线程上(见图 1-2)。这让用户的应用程序执行效率更高,而开发工作量
显著减少。
如果想在执行一段代码的同时,并行去做另外一些事情,goroutine 是很好的选择。下面是一
个简单的例子:
func log(msg string) {
...这里是一些记录日志的代码
}
// 代码里有些地方检测到了错误
go log("发生了可怕的事情")
图 1-2 在单一系统线程上执行多个 goroutine
关键字 go 是唯一需要去编写的代码,调度 log 函数作为独立的 goroutine 去运行,以便与
其他 goroutine 并行执行。这意味着应用程序的其余部分会与记录日志并行执行,通常这种并行
能让最终用户觉得性能更好。就像之前说的,goroutine 占用的资源更少,所以常常能启动成千上
万个 goroutine。我们会在第 6 章更加深入地探讨 goroutine 和并发。
2.通道
通道是一种数据结构,可以让 goroutine 之间进行安全的数据通信。通道可以帮用户避免其
他语言里常见的共享内存访问的问题。
并发的最难的部分就是要确保其他并发运行的进程、线程或 goroutine 不会意外修改用户的
数据。当不同的线程在没有同步保护的情况下修改同一个数据时,总会发生灾难。在其他语言中,
如果使用全局变量或者共享内存,必须使用复杂的锁规则来防止对同一个变量的不同步修改。
为了解决这个问题,通道提供了一种新模式,从而保证并发修改时的数据安全。通道这一模
式保证同一时刻只会有一个 goroutine 修改数据。通道用于在几个运行的 goroutine 之间发送数据。
在图 1-3 中可以看到数据是如何流动的示例。想象一个应用程序,有多个进程需要顺序读取或者
修改某个数据,使用 goroutine 和通道,可以为这个过程建立安全的模型。
图 1-3 使用通道在 goroutine 之间安全地发送数据
图 1-3 中有 3 个 goroutine,还有 2 个不带缓存的通道。第一个 goroutine 通过通道把数
据传给已经在等待的第二个 goroutine。在两个 goroutine 间传输数据是同步的,一旦传输完
成,两个 goroutine 都会知道数据已经完成传输。当第二个 goroutine 利用这个数据完成其任
务后,将这个数据传给第三个正在等待的 goroutine。这次传输依旧是同步的,两个 goroutine
都会确认数据传输完成。这种在 goroutine 之间安全传输数据的方法不需要任何锁或者同步
机制。
需要强调的是,通道并不提供跨 goroutine 的数据访问保护机制。如果通过通道传输数据的
一份副本,那么每个 goroutine 都持有一份副本,各自对自己的副本做修改是安全的。当传输的
是指向数据的指针时,如果读和写是由不同的 goroutine 完成的,每个 goroutine 依旧需要额外的
同步动作。
1.1.3 Go 语言的类型系统
Go 语言提供了灵活的、无继承的类型系统,无需降低运行性能就能最大程度上复用代码。
这个类型系统依然支持面向对象开发,但避免了传统面向对象的问题。如果你曾经在复杂的 Java
和 C 程序上花数周时间考虑如何抽象类和接口,你就能意识到 Go 语言的类型系统有多么简单。
Go 开发者使用组合(composition)设计模式,只需简单地将一个类型嵌入到另一个类型,就能
复用所有的功能。其他语言也能使用组合,但是不得不和继承绑在一起使用,结果使整个用法非
常复杂,很难使用。在 Go 语言中,一个类型由其他更微小的类型组合而成,避免了传统的基于
继承的模型。
另外,Go 语言还具有独特的接口实现机制,允许用户对行为进行建模,而不是对类型进行
建模。在 Go 语言中,不需要声明某个类型实现了某个接口,编译器会判断一个类型的实例是否
符合正在使用的接口。Go 标准库里的很多接口都非常简单,只开放几个函数。从实践上讲,尤
其对那些使用类似 Java 的面向对象语言的人来说,需要一些时间才能习惯这个特性。
1.类型简单
Go 语言不仅有类似 int 和 string 这样的内置类型,还支持用户定义的类型。在 Go 语言
中,用户定义的类型通常包含一组带类型的字段,用于存储数据。Go 语言的用户定义的类型看
起来和 C 语言的结构很像,用起来也很相似。不过 Go 语言的类型可以声明操作该类型数据的方
法。传统语言使用继承来扩展结构——Client 继承自 User,User 继承自 Entity,Go 语言与此不同,
Go 开发者构建更小的类型——Customer 和 Admin,然后把这些小类型组合成更大的类型。图 1-4
展示了继承和组合之间的不同。
2.Go 接口对一组行为建模
接口用于描述类型的行为。如果一个类型的实例实现了一个接口,意味着这个实例可以执行
6
第 1 章 关于 Go 语言的介绍
一组特定的行为。你甚至不需要去声明这个实例实现某个接口,只需要实现这组行为就好。其他
的语言把这个特性叫作鸭子类型——如果它叫起来像鸭子,那它就可能是只鸭子。Go 语言的接
口也是这么做的。在 Go 语言中,如果一个类型实现了一个接口的所有方法,那么这个类型的实
例就可以存储在这个接口类型的实例中,不需要额外声明。
图 1-4 继承和组合的对比
在类似 Java 这种严格的面向对象语言中,所有的设计都围绕接口展开。在编码前,用户经
常不得不思考一个庞大的继承链。下面是一个 Java 接口的例子:
<pre><code class="language-cpp">interface User { public void login(); public void logout(); }</code></pre>

在 Java 中要实现这个接口,要求用户的类必须满足 User 接口里的所有约束,并且显式声
明这个类实现了这个接口。而 Go 语言的接口一般只会描述一个单一的动作。在 Go 语言中,最
常使用的接口之一是 io.Reader。这个接口提供了一个简单的方法,用来声明一个类型有数据
可以读取。标准库内的其他函数都能理解这个接口。这个接口的定义如下:
<pre><code class="language-cpp">type Reader interface { Read(p []byte) (n int, err error) }</code></pre>

为了实现 io.Reader 这个接口,你只需要实现一个 Read 方法,这个方法接受一个 byte
切片,返回一个整数和可能出现的错误。
这和传统的面向对象编程语言的接口系统有本质的区别。Go 语言的接口更小,只倾向于
定义一个单一的动作。实际使用中,这更有利于使用组合来复用代码。用户几乎可以给所有包
含数据的类型实现 io.Reader 接口,然后把这个类型的实例传给任意一个知道如何读取
io.Reader 的 Go 函数。
Go 语言的整个网络库都使用了 io.Reader 接口,这样可以将程序的功能和不同网络的
实现分离。这样的接口用起来有趣、优雅且自由。文件、缓冲区、套接字以及其他的数据源
都实现了 io.Reader 接口。使用同一个接口,可以高效地操作数据,而不用考虑到底数据

来自哪里。



1.1.4 内存管理


不当的内存管理会导致程序崩溃或者内存泄漏,甚至让整个操作系统崩溃。Go 语言拥有现
代化的垃圾回收机制,能帮你解决这个难题。在其他系统语言(如 C 或者 C )中,使用内存
前要先分配这段内存,而且使用完毕后要将其释放掉。哪怕只做错了一件事,都可能导致程序崩
溃或者内存泄漏。可惜,追踪内存是否还被使用本身就是十分艰难的事情,而要想支持多线程和
高并发,更是让这件事难上加难。虽然 Go 语言的垃圾回收会有一些额外的开销,但是编程时,
能显著降低开发难度。Go 语言把无趣的内存管理交给专业的编译器去做,而让程序员专注于更

有趣的事情。



<span style="color:rgb(51,51,51);font-family:'SF Pro Display', Roboto, Noto, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;font-size:14px;background-color:rgb(255,255,255);">尹成老师</span>

<span style="color:rgb(51,51,51);font-family:'SF Pro Display', Roboto, Noto, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;font-size:14px;background-color:rgb(255,255,255);">QQ77025077 </span>

<span style="color:rgb(51,51,51);font-family:'SF Pro Display', Roboto, Noto, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;font-size:14px;background-color:rgb(255,255,255);">微信18510341407</span>

<span style="color:rgb(51,51,51);font-family:'SF Pro Display', Roboto, Noto, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;font-size:14px;background-color:rgb(255,255,255);">所有视频在尹成学院</span>

<span style="color:rgb(51,51,51);font-family:'SF Pro Display', Roboto, Noto, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;font-size:14px;background-color:rgb(255,255,255);">www.yinchengxueyuan.com</span>

<span style="color:rgb(51,51,51);font-family:'SF Pro Display', Roboto, Noto, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;font-size:14px;background-color:rgb(255,255,255);">尹成百度云请联系QQ475318423</span>

<span style="color:rgb(51,51,51);font-family:'SF Pro Display', Roboto, Noto, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;font-size:14px;background-color:rgb(255,255,255);">
</span>

<span style="color:rgb(51,51,51);font-family:'SF Pro Display', Roboto, Noto, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;font-size:14px;background-color:rgb(255,255,255);"></span>


到此这篇关于“兄弟连golang神技(1)-关于 Go 语言的介绍”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
兄弟连Go语言培训带你实战GO案例(7)Go Defer
兄弟连golang神技(1)-关于 Go 语言的介绍
go 语言学习历程
jquery的父子兄弟节点查找示例代码
想系统学习GO语言(Golang
Golang 基础教程
js获取兄弟节点、父类节点的方法
Go语言-零基础入门视频教程
Viper——Go语言写的配置文件读取写入工具神器
jQuery父级以及同级元素查找介绍

上一篇:golang 数组面试题 下一篇:Golang GC原理
[关闭]
~ ~