Golang: Think in Golang

听听七牛的老总许式伟 《thinking in go》。

说实话看到他用 thinking in 这样的开头比较担心
因为看过 thinking in C++,即 《C++编程思想》,啰嗦!

整个看过来之后,发现收获超级多

Anyway, 看看国内的先驱是怎么讲 Golang,不是很有趣么? 视频地址。(1小时46分钟)

讲的还是比较长的,将近两个小时,我把它概括如下:

  • go语言追求简单,特性简单 (如果一个特性加入进来只是少些几行代码的话而没有其他特殊价值,go语言一定不会加入)
  • 自然 nature,平实 (大家自然能接受方式,而不是炫技花哨,例如什么什么重载啊之类的)
  • 不容易犯错 (不 care 语法糖)

golang 是基于连接和组合的语言: (rob pip提出来的,现在 golang 的负责人):

编程语言范式:

  • 过程式,比如 C — (只要有函数就有这种范式的影子)
  • 面向对象 — (三大特性: 继承,封装,多态;包括各种重载机制,接口等等)
  • 面向消息 — erlang (并发编程语言,如果不用锁,共享内容等机制,那么就用消息队列) —只要有锁&同步,其实代码还是串行执行的(效率必然不高),鼓励基于消息传递的机制来编程,而不是锁
  • 函数式 — haskell (闭包,变量不可变等) 小众.

  • 有锁,所以面向消息不纯粹
  • 有闭包,但是变量不可变等,所以也不是纯粹的函数式
  • 面向对象也不纯粹,因为反对继承;最多也就是可以添加成员方法

Golang 是都范式的,和 C++ 类似。高手无门无派!

连接: (格式 && 协议 && 哲学) 应该自描述

其中 pipeline 其实是并行执行的,不是前一个完成了才进行下一个。

上面的哲学(unix哲学: 单一任务; 关注流,输入输出),代码如下:

bind: (降低维度)


pipe: (组合出复杂操作 – 并行执行)

其中 defer 可以理解成,用之前,先安排好善后工作

有更复杂的,一进入生成更多的小函数,每个小函数代表一个应用:

这段代码,如果 goroutine 起不来了,可能会出大问题,善后工作也是。

filter: (筛选 && 过滤)

filter 的作用和 pipe 类似,也是同时处理,但是它是 串行 的。(做一段,处理一段)

  • pipeline 有通道,通讯成本,切换执行的成本;
  • filter 不用交给别人,但是本身是串行的。

就像一个大文件,压缩处理,开多个线程一定好么?压缩计算成本 VS 多线程间通信交换数据成本。

  • 通讯的成本(保存上下文,切换的成本) — 通信读写量很大的话,通信成本就高了,少通信
  • 任务本身的成本高 (如果都是简单任务,加加减减之类的简单操作,根本不用交给另外的人并行操作了)

golang 用于 unix 的标准连接方式很简单,实现并行化也非常容易。

协程:

协程底层是线程池或者线程,但是调度不归你管。(更多的可以理解成 worker 线程接手执行体)

大佬言谈之中,深刻的透露了自己后端大佬的底气,简单的说,原始的服务器变成模型哪里谈的问题,进程 fork 的开销,上下文切换的开销(IO密集型 — 本来一个正常的逻辑,频繁的被 IO 操作打断,来回保存上下文,多累啊),没办法,异步回调+执行体吧,(但是计算密集型,大量的计算工作,而IO读写少,即很少被打断,那就要多开几个线程&进程,并行执行啊) — 但是写的很累啊,并发控制容易累啊。所以引入了协程。关注执行体,不关注线程。不管这段代码是交给哪个线程执行,所以引入协程,协程本身和回调思想也类似,切换回去的代价也比较小。

异步回调其实是自己控制了切换的上下文,但是多进程&线程其实是让栈来维护上下文。并且线程&进程你敢随便多起,因为栈大小内存大小决定了你的上限,但是 goroutines 可以,它切换成本很小(本质上和回调实现类似)—所以 goroutines 之间通信要用自己的 chann 机制,而不用其他现有机制。

接口:

连接,在接口这里体现的最明显;明显区别于其他语言。

没有冗余,没有侵占;不用声明 & 定义,直接用就行了。

写类的时候,完全不需要知道其他额外的任何信息;接口?不需要。

接口本身也只是说我需要你们做什么,别人是否做到了(是否支持 area 方法),接口本身不管的。

约定强于配置,最好是弱联系

接口最好是自描述,不需要借助额外的内容&定义就能知道能干什么,要干什么。比如说,这个接口要求是三个孔的物件,你不需要提前过来打招呼说,我是具备三个孔的物件,我可以连接等等一系列说明,直接过来连接就好了。

不需要经历: 先定义接口,然后写某个类去实现它

组合:

组合,然后可以为这样的类型指定成员方法(receiver),这就是 go 面向对象的全部。

匿名组合的时候,成员属性 & 方法是直接归属于上级的,有点儿继承的意思。

有点儿类似 C++ 的虚继承 (避免菱形继承那里的虚拟继承),即从上级那里继承的其实是指针。

组合的话,注意一下,内部成员名字重名很难办啊(有些可以解决,有些没办法要特别指定)。
这就是非常强的组合(甚至是盲目聚合)。

继承还有一个内存布局的问题,基类的布局始终是要排在前面的;但是组合不存在。

没有继承(自然也就没有虚函数),能使用多态么? 可以的。用 interface 实现。 一样的用接口对象&引用接收实现类对象的实例,然后进行调用。运行时自动根据范式调用到相应的方法。而且这种方法更加优越,特别是环境不稳定的时候,即接口&虚方法不稳定,有变动的时候:

(当然这种方式本身有问题,不够灵活;现在 GUI 设计都采用的 bind function 的方法,比如信号和槽,比如 object-c 的delegate;而不是直接绑死调用)


Merlin 2018.3.10 吃晚饭的时候听了个培训,大佬不仅仅谈了golang;值得二次再看

文章目录
|