说说 Golang 的使用心得

本贴最后更新于 3315 天前,其中的信息可能已经时移世改

13年上半年接触了Golang,对Golang十分喜爱。现在是2015年,离春节还有几天,从开始学习到现在的一年半时间里,前前后后也用Golang写了些代码,其中包括业余时间的,也有产品项目中的。一直有想法写点Golang相关的总结或者感想,决定还是在年前总结下吧。注明下:我只是Golang的喜好者,不是脑残粉,也无意去挑起什么语言之争。

特性少,语法简单。GO是崇尚极简主义的,提倡少即是多。这点在它的Spec上尤其凸显,一下午的时间绝对可以看完。GO的特性很少,很多GO的使用者都反馈,GO的关键字至少完全可以记在大脑里。同时它的语法极为简单,而且语义清晰。

部署方便。GO是一个强类型静态语言,可以把代码编译为本地机器指令。它的RUNTIME是会在编译时一起链接到执行文件中,这也就意味着我们不需要像JAVA那样装一个JVM。而且编译出的执行文件本身不依赖于其他动态库,完全可以做到轻松的发布。当然,如果你用GO编写了调用一些动态库接口的代码,那么还是需要根据实际情况来部署这个动态库的。这点在很多从python/java转到go的朋友来说,非常喜欢。

有较完善的标准库并且较为健壮。GO自身带的标准库是比较全面的,从文件归档、压缩、加密、数据库到数据序列化,字符格式化、校验和以及网络库、同步库等应有尽有。基本上能够满足很多基本的需求了。更好的是,这些标准库的质量都非常高,都很健壮。接口也较为简单,有清晰的文档说明。同时随着这两年的发展,GO的第三方库也多了起来,虽然可能没有像python那么多,但是较其发展时间来说,还是非常不错的。

集成测框架。在之前用C++写代码时,写单元测试不是个容易的工作。需要一些技巧和努力才可以做起来。但是在GO中集成了单元测试框架,只要源码文件以_test.go结尾,就可以直接通过go test执行单元测试。同时还提供了代码测试覆盖率工具,可以很容易实施自动化测试。除此之外,还集成了基准测试框架功能,可以很容易的测量自己写的函数的运行效率。另外,还有性能剖析器,可以在运行时,测试时剖析程序的瓶颈点,进而可以进行优化。

健全的代码风格与检查工具。当初学GO的时候,很多文章和书都会提到go fmt这个命令,统一了代码风格。我觉着这点实在是解决了风格之争了。带来的影响就是别人写的代码感觉也是自己写的一样。还有golint,可以按照go team的风格和要求来写代码。还有go vet可以用来检查一些在GO中很隐蔽的坑。

简单却强大的包管理。GO的包管理可能在很多其他语言的包管理看来太弱了,但是在我看来,它解决了我需要的两个问题,一个是循环依赖问题,GO是拒绝有循环依赖关系的包;二是包的初始化,每个包的文件都可以实现一个init函数,用来在导入时执行。这点在分工合作时非常有用。

容易编写跨平台代码。如果你用纯GO,不牵扯到CGO的话,你可以非常容易的做到跨平台。只需要在文件后缀.go前,引入_linux,_windows,_x86,_x64等字符为文件名前缀的结尾就可以做到只在对应的平台中编译。GO还有build constraints控制代码在什么条件下编译。如果你用到了CGO,就牵扯到了C的跨平台问题,所以稍微麻烦那么一些,但是问题也不是太大。

垃圾回收。GC的存在极大的降低了并发代码的编写,而且还提供了程序的健壮性。做为一个从C/C++做起,有过驱动开发经验的程序员来说,GC这个东西是我一直没有涉猎过的。对我来说GC就等于噩梦。但是当我开始试着接受GC时发现,GC真的是解决了程序员的生产力,极大的提高了效率。虽然目前来说GO已经1.4版本了,但是GC还算不得上优秀,按照GO的路线图,后面会有更优秀的GC实现添加进来。

接口与struct。在第一次学习GO的interface的时候,我第一反应是这就是我想要的。虽然很多人也在说GO的这个interface的不好,而且说的很有道理,比如老赵的《为什么我不喜欢GO语言式的接口》。interface可以通过组合扩展为新的interface,struct也可以通过组合扩展为新的struct。没有继承,只有组合。可以通过匿名组合达到类似继承的效果。可以对interface进行查询,有点类似COM的味道,但是语法层面上更为简单。struct到interface的映射是隐式的,不需要声明某个struct实现了某个interface。虽然可能会出现名字上的冲突,但是可以通过wrapper进行解决。这种interface的另外一个好处是单元测试时很容易实现MOCK,这点非常喜欢。也可以看这篇文章《Go interfaces make test stubbing easy》

统一的工作布局。GO定义了项目的目录结构,比如bin目录,pkg目录以及src目录。这个和我日常的项目布局是一致的。之前用C++开发时我们也是如此安排布局,所以就这点来说,我觉着容易过渡。

内建的并发原语。提到GO就不得不提到goroutine和channel。廉价的goroutine可以让我们欢快的处理异步任务,channel可以用来交换数据。借助goroutine,可以很容易的实现高性能的服务端。goroutine及其调度器可以很容易和EPOLL,IOCP等系统机制结合起来,再通过Half Sync/Half Async模式,很容易在语法层面上达到同步形式,却不失性能。

2013年初的时候还在做一个客户端,当时使用了C++0x,其中印象最深的事情是lambad,std::function/bind,结合着线程+队列的方式,可以很容易的实现类似于Chromuim的线程模型。在处理UI与慢任务比如读文件,请求网络数据等交互时,为了保证UI的体验,使这些任务异步化是非常有必要的。如果有对Golang了解或熟悉的朋友就会明白,这是类似与Golang的goroutine+channel。但是在使用这个模型时,觉着还是繁琐了些,我要注意对象的生命周期,这个在C++虽然有各种智能指针的帮助,但是难免还会挂一漏万。而且遇到稍微的复杂的问题,比如一个慢任务接着一个慢任务时,就会涉及到一个任务链,在没有future/promise(Facebook开源的folly库中有个不错的实现futures,后来还发现WINDOWS有个基于actor model的并发库Asynchronous Agents Library非常不错,只可惜目前只在WINDOWS上使用。)机制的帮助下很容易进入Callback Hell。这样就会导致代码相对来说比较难维护,而且容易滋生BUG。好在当时这个部分的代码不是太多,而且也不是太过于复杂,很容易通过自测稳定下来。

上面虽然提到future/promise, AAL可以解决部分Callback Hell的问题,但是像future还是要用到callback。所以我在想,如果可以做到代码层面上是同步式的,背后却是异步的就爽了。GO就满足了我这个需求。

GO标准库中还提供了sync包,其中有基本的mutex说,还有RMutex这样的读写锁,还有Once,WaiterGroup等东西。基本满足日常中对锁的需求了。

GO为了帮助程序员解决在并发时经常遇到的race condition问题,还提供了相应的race condition工具。还有相应的死锁检测工具。

虽然GO社区有个slogan:”do not communicate by sharing memory; instead, share memory by communicating.“,但是每个goroutine之间并不是完全独立的,一样可以做到通过内存共享数据。这个时候只能依靠程序员自己去遵守了。而且因为goroutine不是完全独立,panic这种东西就可能会导致整个程序挂掉。这点和Erlang比起来确实不是很好。

蛋疼的defer。用习惯了C++的RAII后,十分反感GO的defer机制,但是有的时候又不得不用。原因就是这个defer不是block级别的,而是函数级别的,需要在函数返回前才得到执行。所以这就会导致在处理一些类似于文件打开,操作再关闭的逻辑时非常蛋疼,回到了C的年代,必须手动去Close。

蛋疼的panic。虽然我在C++下不怎么用异常,但是对于panic这个设计我表示非常的不满意啊。因为它会影响全局。而要捕捉panic就需要用defer。如果panic只是让当前goroutine挂掉我觉着就嗨皮坏了。

没有泛型。GO没有泛型带来的蛋疼地方是,要么就用interface{}来做运行时泛型,要么就自己手动写代码生成器。比如我自己为了生成网络协议序列化代码就撸了一个生成器。而且因为没有泛型,想实现类似C++ STL的容器与算法基本没太可能,当然方法还是有的,继续使用代码生成器。而且GO1.4干脆引入了一个叫go generate的命令。

总结

GO里面其他一些内建的数据结构,比如slice,map等,但这些也是诟病,因为它又没给予程序员可以享用range关键字的福利。

在GO的所有特性里,最喜欢就是GC,goroutine,channel以及interface。而其余的特性(比如上面我列举的很多特性)我觉着都不是太重要,其中很多都可以在工程中实践,和语言本身没有太大关系。

总结下来,这东西就是一个工程工具,各种好用,但是从设计角度讲各种粗糙,没必要过度高估。它算的上工程实践中的好朋友。在写服务端时,它是把利器,至少在写服务端程序时,我自己感觉如此。

有朋友说一个语言好不好就看它有没有开拓你的眼界,给予你新的思想,我想至少GO在这点上满足了。

  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    497 引用 • 1388 回帖 • 279 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 559 关注
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 164 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    12 引用 • 54 回帖 • 159 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖 • 7 关注
  • 电影

    这是一个不能说的秘密。

    121 引用 • 604 回帖 • 1 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 464 关注
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    36 引用 • 37 回帖 • 535 关注
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 161 关注
  • CongSec

    本标签主要用于分享网络空间安全专业的学习笔记

    1 引用 • 1 回帖 • 15 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    93 引用 • 113 回帖
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 683 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 53 关注
  • 工具

    子曰:“工欲善其事,必先利其器。”

    288 引用 • 734 回帖 • 2 关注
  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    25 引用 • 7 回帖 • 159 关注
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    58 引用 • 22 回帖
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    88 引用 • 1235 回帖 • 410 关注
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    132 引用 • 1114 回帖 • 125 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    76 引用 • 1737 回帖 • 1 关注
  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    53 引用 • 37 回帖 • 3 关注
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    91 引用 • 751 回帖 • 1 关注
  • 自由行
    4 关注
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    77 引用 • 430 回帖 • 1 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    171 引用 • 512 回帖