说实话看到他用
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;值得二次再看