Go 语言到底适合干什么?

Go语言开发团队花了很长时间来解决当今软件开发人员面对的问题 。开发人员在为项目选择语言时,不得不在快速开发和性能之间做出选择 。C和C++这类语言提供了很快的执行速度,而Ruby和Python这类语言则擅长快速开发 。Go语言在这两者间架起了桥梁,不仅提供了高性能的语言,同时也让开发更快速 。
在探索Go语言的过程中,读者会看到精心设计的特性以及简洁的语法 。作为一门语言,Go不仅定义了能做什么,还定义了不能做什么 。Go语言的语法简洁到只有几个关键字,便于记忆 。Go语言的编译器速度非常快,有时甚至会让人感觉不到在编译 。所以,Go开发者能显著减少等待项目构建的时间 。因为Go语言内置并发机制,所以不用被迫使用特定的线程库,就能让软件扩展,使用更多的资源 。Go语言的类型系统简单且高效,不需要为面向对象开发付出额外的心智,让开发者能专注于代码复用 。Go语言还自带垃圾回收器,不需要用户自己管理内存 。让我们快速浏览一下这些关键特性 。
1.1.1 开发速度编译一个大型的C或者C++项目所花费的时间甚至比去喝杯咖啡的时间还长 。图1-1是XKCD中的一幅漫画,描述了在办公室里开小差的经典借口 。

Go 语言到底适合干什么?

文章插图
 
图1-1 努力工作?(来自XKCD)
Go语言使用了更加智能的编译器,并简化了解决依赖的算法,最终提供了更快的编译速度 。编译Go程序时,编译器只会关注那些直接被引用的库,而不是像JAVA、C和C++那样,要遍历依赖链中所有依赖的库 。因此,很多Go程序可以在1秒内编译完 。在现代硬件上,编译整个Go语言的源码树只需要20秒 。
因为没有从编译代码到执行代码的中间过程,用动态语言编写应用程序可以快速看到输出 。代价是,动态语言不提供静态语言提供的类型安全特性,不得不经常用大量的测试套件来避免在运行的时候出现类型错误这类bug 。
【Go 语言到底适合干什么?】想象一下,使用类似JavaScript这种动态语言开发一个大型应用程序,有一个函数期望接收一个叫作ID的字段 。这个参数应该是整数,是字符串,还是一个UUID?要想知道答案,只能去看源代码 。可以尝试使用一个数字或者字符串来执行这个函数,看看会发生什么 。在Go语言里,完全不用为这件事情操心,因为编译器就能帮用户捕获这种类型错误 。
1.1.2 并发作为程序员,要开发出能充分利用硬件资源的应用程序是一件很难的事情 。现代计算机都拥有多个核,但是大部分编程语言都没有有效的工具让程序可以轻易利用这些资源 。这些语言需要写大量的线程同步代码来利用多个核,很容易导致错误 。
Go语言对并发的支持是这门语言最重要的特性之一 。goroutine很像线程,但是它占用的内存远少于线程,使用它需要的代码更少 。通道(channel)是一种内置的数据结构,可以让用户在不同的goroutine之间同步发送具有类型的消息 。这让编程模型更倾向于在goroutine之间发送消息,而不是让多个goroutine争夺同一个数据的使用权 。让我们看看这些特性的细节 。
1.goroutinegoroutine是可以与其他goroutine并行执行的函数,同时也会与主程序(程序的入口)并行执行 。在其他编程语言中,你需要用线程来完成同样的事情,而在Go语言中会使用同一个线程来执行多个goroutine 。例如,用户在写一个Web服务器,希望同时处理不同的Web请求,如果使用C或者Java,不得不写大量的额外代码来使用线程 。在Go语言中,net/http库直接使用了内置的goroutine 。每个接收到的请求都自动在其自己的goroutine里处理 。goroutine使用的内存比线程更少,Go语言运行时会自动在配置的一组逻辑处理器上调度执行goroutine 。每个逻辑处理器绑定到一个操作系统线程上(见图1-2) 。这让用户的应用程序执行效率更高,而开发工作量显著减少 。
Go 语言到底适合干什么?

文章插图
 
图1-2 在单一系统线程上执行多个goroutine
如果想在执行一段代码的同时,并行去做另外一些事情,goroutine是很好的选择 。下面是一个简单的例子:
func log(msg string) {...这里是一些记录日志的代码}// 代码里有些地方检测到了错误go log("发生了可怕的事情")关键字go是唯一需要去编写的代码,调度log函数作为独立的goroutine去运行,以便与其他goroutine并行执行 。这意味着应用程序的其余部分会与记录日志并行执行,通常这种并行能让最终用户觉得性能更好 。就像之前说的,goroutine占用的资源更少,所以常常能启动成千上万个goroutine 。我们会在第6章更加深入地探讨goroutine和并发 。


推荐阅读