leoay技术圈的第8篇原创文章
字数: 4075
首发于微信公众号【leoay技术圈】
你好,我是 leoay, 这是我鸽了无数天之后开始写的又一篇文章,我保证,这是最后一次鸽…(不骗人!!!)
之前想了好久不知道要写啥,其实之前有一篇文章已经写了一半,但是觉得不好,就束之高阁了,本来想写一个从零开始的 Go 语言的系列文章,但是觉得没有必要,因为零基础的参考资料太多了。
最后,我决定还是写我当前用到最多,而且我认为也比较重要的一些东西吧,我觉得这样的话是一件一举多得的事情,性价比更高。
今天分享的这篇文章其实是我从前几天在公司内部分享的文章中截取的一部分,也是一个关于Go语言的很基础的介绍,正好适合这个号,所以就偷个懒,直接拿来了。
今天我想跟大家分享一些关于 Go 语言的一点知识,主要是为了说明一下“我为什么建议你学习一下 Go 语言”吧,我主要想从以下几个方面展开:
- Go 语言的简单介绍
- Go 语言的跨平台
- Go 语言的网络编程
- Go 语言的并发编程
- 关于 Go 语言的学习资源分享
由于我学习 Go 语言,并在工作中运用也不是很长时间,零零碎碎大概一年吧,所以文章中一定有理解和表达不合适的地方,当然更会有不全面的地方,还请大家谅解,如果大家发现不对的地方,还请多多指教,当然我更希望我的文章能帮助到你,让 Go 语言的各种优势能在我们日常的工作中大放异彩,下面我们就进入正题。
Go 语言的简单介绍
Go 语言,也称 Golang, 最初是在2007年由Google的三位工程师 Robert Griesemer、Rob Pike 和 Ken Thompson 设计开发,他们的初衷是想用一种新的语言提高开发可靠、健壮和高效的软件。
刚开始,这仅仅是这个开发小组维护的一个小项目,但是后来慢慢觉得这个项目很有发展潜力,所以 2009年11月10日,Google 在开源博客上发布了这个项目,之后便有来自全球的开发者参与维护和开发。
Go 语言官网对这门语言的评价是:“Go 是一种开源编程语言,可以轻松构建简单、可靠和高效的软件”。从这里我们也能看出 Go 语言的一些特点, 简单、可靠、高效,除此之外,Go 语言还有很多其他特点,比如:
-
静态类型
-
清晰的语法(语法格式比较严格)
-
跨平台,本地交叉编译方便
-
编译效率高
-
运行时无依赖
-
支持垃圾回收
-
有丰富强大的标准库
怎么样,看到这么多优点大家是不是觉得Go语言简直就是“理想型”,其实Go语言的设计灵感主要来源于 Oberon、Pascal、C还有Alef等,也算是取各语言之长吧,集这么多优点于一身,其实Go语言也只是为了解决开发应用时在构建软件时遇到的复杂问题和构建大规模应用时的复杂性问题。
如果你使用过Go语言一段儿时间,一定会被它的简单和高效吸引,它不会让你纠结于语言本身的诸多特性,不像 C++ 一样给你铺设各种各样的坑,也不像 Java, Python,即使语法上像 Python 一样简洁,但是从硬件本身上来讲,它更像 C 语言,编译出应用就是可执行的二进制文件。
从编程范式上说,Go语言和C一样都是 “过程式语言”,Go 语言也想C 一样都是没有“对象”的“单身狗”,但是请不要以为Go就不支持面向对象编程了,相反,继承、多态以及基于对象,这些特征一点不少,可以说 Go 语言是一门骨子里有面向对象精神的过程式编程语言(来自突发奇想地胡扯)。
Go语言的跨平台
好了上面吹了那么多Go语言的优点,接下来我们也不说Go语言的缺点了,我们聊聊Go语言的跨平台。
为啥跨平台?因为编译器跨平台呗,像C和C++一样,Go的代码都是经过自己的编译器编译成机器能识别的二进制文件,然后直接运行。
这一点其实没啥好说的,我要说一点比较牛的地方,就是Go是自带交叉编译工具的。比如我在macOS上写了一段 go 代码,我想编译出能直接在 Windows上运行的程序怎么办呢?按照C语言的常规操作,就是先安装交叉编译工具链,修改Makefile 然后 make。
但是Go就不一样了,它只需要在编译命令前跟上几个参数就可以交叉编译了,下面列举编译不同平台的命令参数:
编译Linux程序
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build filename.go
编译Arm Linux程序
CGO_ENABLED=0 GOOS=linux GOARCH=arm go build filename.go
编译Window程序
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build filename.go
编译MacOS程序
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build filename.go
上面的命令可以在任何平台上直接运行,就可以编译出目标平台的程序了,怎么样,是不是很方便?妈妈再也不用担心我们折腾工具链搞半天了,我们只需要专注于自己的业务代码了,Goooooo!
Go语言的网络编程
提到Go语言,我就不得不吹一下Go语言的网络编程了,我觉得像Go语言这样的网络编程极其简单高效的语言不多了,大家且用且珍惜。
为啥高效呢?我先写一段儿代码吧!
比如,我想用最原始的Go代码(不用任何第三方web框架)写一个web服务,我可以这么写
package main
import (
"io"
"net/http"
"log"
)
func HelloLeoay(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "hello, leoay!\n")
}
func main() {
http.HandleFunc("/hello", HelloLeoay)
err := http.ListenAndServe(":6666", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
简单几行代码就能写一个,能接收 get 请求的web server, 如果使用更高效的第三方 web 框架,将更加如鱼得水,比如 gin、Iris、beego、gRPC(Google开源的RPC框架)、Kratos(B站开源的微服务框架)等等。
当然,Go语言发送get、post等网络请求也是非常方便的,这里就不再展开写了,大家感兴趣的可以去查一下。
Go语言的并发编程
下面,我想重点介绍一下Go语言的并发编程特性。虽然说 Go语言有众多优点,但是很大一部分人选择 Go语言作为自己的目标语言主要还是看重其在并发编程上的先天优势。
说到并发编程,其实主要包含三个方面:
(1)多线程编程
(2)多进程编程
(3)分布式编程
不过本篇文章就不展开那么多了,就简单谈一下Go语言最常用的多线程编程,其实我们日常的工作中最常用的并发编程也是多线程。
其实 go语言中的线程跟我们经常接触的 C/C++ 中的线程、java中的线程是不一样的,在Go语言中 其实是使用 goroutine 代表线程,但是goroutine是比线程更细粒度的,它允许我们以非常低的代价在同一个地址空间中并行地执行多个函数或者方法。相比于线程,它的创建和销毁的代价要小很多,并且它的调度是独立于线程的。在golang中创建一个goroutine非常简单,使用“go”关键字即可:
package main
import ( "fmt" "time")
func learning(){
fmt.Println("My first goroutine")
}
func main() {
//创建一个goroutine 执行 learning 函数
go learning()
time.Sleep(1 * time.Second) fmt.Println("main function")
}
如上代码所示,我们只需要在函数之前加上go关键字,就创建了一个线程,而其他语言,如C/C++、java、python等与之相比则要复杂一些。
下面简单说一下 Go 语言线程间通信,这个还是比较有特点的,我们知道C/C++中的线程间通信是基于内存的,这个就容易导致很多难以定位的问题,其中最臭名昭著的就是“踩内存”。
但是,Go语言就没有这个烦恼了, 因为Go 是基于消息进行线程间通信的,Rob Pike有一句名言是这样说的:“Don’t communicate by sharing memory; share memory by communicating. (R. Pike)”。
什么意思呢?说白了就是说在 Go 语言中不要使用共享内存的方式进行通信,而要通过通信的方式共享内存,其实就是说明了 Go语言中进程间通信的方式。
那么还如何做呢?其实Go语言中有一个关键字 channel, 含义是通道,其实就是用于通信的,上面提到的进程间通信就可以通过这个channel实现,具体看代码:
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c
fmt.Println(x, y, x+y)
}
代码中有一个 channel 变量 c,就是用来传递两个sun进程内的消息的,就好像一根电话线一样连接而者,实现进程间通信。
怎么样,你觉得这样做是不是很巧妙,安全,而且还很简单。
关于 Go 语言的学习资源分享
最后,我就简单分享一些我学习Go语言时参考的资源吧,也希望能给想入坑的朋友一些帮助。
golang.google.cn/
最先推荐的当然是Go语言官网了,里面有各种入门小技巧以及非常详细的参考文档,从安装,到写第一行 Hello World, 再到写自己的模块,写一个web服务应有尽有,比较推荐的一本书就是里面的《Effective Go》,可以说是入门必备。
此外Packages 则是所有标准库的参考文档,遇到不熟悉的标准库,在这里面找答案就对了。
books.studygolang.com/gopl-zh/
第二本书就是《Go语言圣经》,也是一本很经典的入门书,总之学就对了
draveness.me/golang/
第三本是 draveness 的《Go 语言设计与实现》,这是 draveness 的个人博客上分享的书,写得很不错,无论文章排版,还是配图,以及内容深度,都很不错,推荐。
github.com/Terry-Mao/goim
第四个推荐一下B站的开源项目 goim, 就是用Go写的一个 IM (即时通信) 框架,你可知现如今B站那猛如洪流的弹幕可是基于这个框架开发的?至于其他优点,大家可以直接上 github 浏览。所以,不要犹豫的,赶紧学它就是了。当然,其中还涉及kafka、gRPC、Discovery等其他组件,所以完全学会还是不太容易的
github.com/go-kratos/kratos
最后推荐一下 kratos 这个微服务框架,也是B站开源的,目前B站后台许多微服务都是基于这个框架开发,按照官方的话有如下优点:
-
简单:不过度设计,代码平实简单;
-
通用:通用业务开发所需要的基础库的功能;
-
高效:提高业务迭代的效率;
-
稳定:基础库可测试性高,覆盖率高,有线上实践安全可靠;
-
健壮:通过良好的基础库设计,减少错用;
-
高性能:性能高,但不特定为了性能做 hack 优化,引入 unsafe ;
-
扩展性:良好的接口设计,来扩展实现,或者通过新增基础库目录来扩展功能;
-
容错性:为失败设计,大量引入对 SRE 的理解,鲁棒性高;
-
工具链:包含大量工具链,比如 cache 代码生成,lint 工具等等;
好了,今天就简单分享这几点吧,因为是第一篇,所以没有写很深,更偏向于科普性质,不过我觉得可以帮助大家对Go语言有一个粗浅的认识,其实每一部分都可以详细展开的,这个等后面有时间再单独写吧。
Go 作为互联网时代的C语言,无论是在微服务,还是云原生都有着先天的优势,如果大家有 web 端或者高并发等业务需求,可以考虑一下如果用Go语言开发是不是更有优势。
好了,今天的分享就到这里,感谢大家阅读,如果有什么疑问也欢迎大家和我讨论交流。
上面就是摘录的文章,其实对于 Go 语言,我觉得它最大的有点就是语法简单,环境配置简单,代码比较简洁,不需要我们写很多没有用的代码,我觉得这也是大部分人很快喜欢上 Go 语言的原因。
但是,不管喜不喜欢,我们的目标是解决问题,然后用它产生价值,语言只是千万工具中的一种。
后面的文章,我会继续深入分享 Go 语言在实际项目中的各种应用,以及一些开源的小项目,欢迎大家关注,我们一起成长,一起加油吧!