Go的编程语言层面
编程语言的一些理解
所谓编程语言,当然它得是一门语言,语言的根本目的是交流(包括储存)。我们使用语言的时候一般有两种方式,一种是表述:比如描述一个物体,介绍一个过程,或者表达一种观念;另一种是命令:比如从哪里拿一杯水来给我。这两种语言模式也形成了目前最流行的两种类型的编程语言:指令编程语言和函数编程语言
指令编程语言:被称为冯诺依曼式编程语言,其实指令编程语言可以更早地追溯到图灵,冯诺依曼设计的计算机是以图灵机为原型的,而我们现在使用的几乎所有的指令型编程语言都是以图灵机为物理模型,我们的所有代码都是指令操作+操作地址,而指令操作就可以完全对应成图灵机的机器头的操作,而操作地址就可以对应成纸带的移到。
函数编程函数:不同于指令编程语言是基于图灵机,函数编程是基于λ演算,λ演算也就是我们平时所熟知的λ表达式,或者闭包运算。函数编程考虑的不是如何去描述操作或控制读写,而是更偏数学一点更去关注如何处理数据。在数学中,对数据的处理被理解成函数,函数是定义域到值域的映射,因此在函数式编程中,函数变成了主要研究对象。不像在指令编程中函数只是一系列指令操作的封装,在函数式编程中的函数变成了一级对象,可以被赋值操作转化。函数编程还有一点在于其不允许输入值变化,也就是不允许副作用函数,一个函数只能由输入返回一个结果。因此,函数式编程特别适用用于并发环境,因为只要函数都是没有副作用的,就不会存在并发的安全边界,所有的并发操作之间不会产生相互影响。但由于函数式不允许副作用,更进一步讲其实是不允许并发之间共享数据,因此会对cpu和内存占用造成较大负担。
Go是面向过程的还是面向对象的
而Go其实算是指令编程语言,Go继承了C的大部分特性,包括数据类型、复合数据结构的定义和操作,函数与递归。指令编程语言还有两个较大分类:面向过程和面向对象。Go如果非常在这两种类型中选择一个,Go更偏向于是面向过程的。面向对象的三大特性是:封装、继承与多态(我在大学时这三个特性是在Java中讲的,我更倾向于这三个是Java的面向对象特性的学术描述),但Go不支持语言级别的继承(匿名字体不算继承,更像是多态的一种实现)。不能说只要具有封装、继承、多态的语言就是面向对象语言,以我的理解,面向对象更应该称之为一种编程思想,只是有些语言在语法层面给了面向对象编程思想以较容易实现的语法和特性。因此Go说到底其实还是属于面向过程的语言,至少在语法和特性层面是这样的。
Go语言的特点
Go是google的一群工程师期望使用一门更简洁的编程语言而被设计出来的,因此取名也取自google。 Go语言的创始人和维护团队在开发者对于支持面向对象特性语法的提议也是持较为保守的态度,不仅如此,Go对于其他方面的改动也特别谨慎,比如对于泛型的支持,直到最新的Go1.8才开始支持,而且也只是很小程度的支持。Go开发团队对于Go的期望一直都是安全和简洁,Go的学习上手难度极低,由于Go从C继承来了非常多的特性,因此只要有C语言基础的开发者,能够在一个下午就能学习使用Go开发一些简单应用。
Go相较于Java
我曾经和现在一直是一个非常坚定的Java(或者是基于jvm)技术栈Coder,这里说的坚定不是指坚持用某个编程语言而不重视或者抗拒用其他编程语言。
- nb的Java
Java有非常大的技术社区和应用场景,正如Java最开始被设计出来用于机顶盒系统应用开发的,现在的Android原生开发还是以Java(jvm)为主,Java在服务端的开发则更是多元,现在绝大部分的服务端项目基于Java的,国内熟知的几乎所有互联网企业(字节跳动除外)后台项目,还有所有(这里不是几乎)的政企事业单位,就连我们现在每天使用的各地健康宝和绿码,我猜99.9%的可能性也是基于Java开发的。同时,Java对于语言层面的支持也是属于非常激进的,不论是先进的基于CPU指令的并发控制还是函数式函数和基于流的集合操作,Java的支持都是走在编程语言界的前列的。
Java的nb最根本还是在于其jvm,jvm可以说是世界目前最先进的进程级虚拟操作了。特别是jvm的垃圾收集器,虽然我未参与过Java服务端的大型项目,但据国内阿里腾讯百度之类的大厂多年来使用Java构建了无数大型项目来说,jvm的垃圾收集器绝对是顶级的。
-
我对Java的一些吐槽
-
Java的上手门槛其实一点都不低:虽然Java有compile once,run anywhere的特点,但想要写好Java并非易事。由于Java是基于jvm的,jvm是在操作系统的进程级虚拟机,由于中间切切实实隔了一层,因此有时候会出现各种奇奇怪怪的问题,比如明明内存还没超过OOM的限制,还是触发了OOM导致整个进程异常exit。写出性能好的Java程序更是一些难事,Java程序的性能一般体现在内存占用和并发控制两方面。内存占用方面,虽然有了jvm的垃圾回收器,但成也垃圾回收器败也垃圾回收器,初学者以为有nb的垃圾回收器就可以高枕无忧了,但内存泄露依赖是所有程序员的痛,只是nb的垃圾回收器能更智能地自动回收内存而已。只要我们的代码中还有对对象的内存的强依赖,即使垃圾回收器再智能,也不能帮我们自动释放无用的内存。另一点的并发控制,Java虽然有比较完善的并发支持,但Java原生的线程还是系统级别的,线程的创建和释放都开销巨大,在应用层面虽然早已有线程池技术,但线程的调度依赖是个难题,Java也一直没有给出jvm或者语法层面的线程调度方案。总的来说,Java在语言层面是特别开放和激进的,但留下的坑真的不少,也就是nb的程序员能用Java写出特别nb的系统,菜鸡的程序员也能用Java写出很菜鸡的代码。
-
Java很不安全:这里的安全不是指内存访问和系统调用的安全,Java在内存访问和系统调用上其实是非常安全的,java语言和机制层面导致的安全问题是非常少的,要比C/C++要少得多,我们听到的像是log4j的安全漏洞问题几乎都是应用级别的。由于Java几乎完全继承了C/C++的对象体系,因此就避免不了数组越界和类型强转。所有的Coder都会低估软件系统的复杂性,因此这些C/C++遗留下来的不安全操作总是会导致一些线上问题。就算在写代码时注意了强转和数组访问问题,但不懂封装的程序员不是好程序员嘛,我们的代码总是会被其他人和以后的自己调用,代码引起的bug几乎都是改代码引起的。
-
Java的反射很鸡肋:Java是静态语言,但它使用反射机制保留了部分动态语言的特性,这在大部分时候都是好用的,但Java的反射会急剧降低性能,但我们大部分时间又对反射解决问题的方便快捷很上瘾,因此大部分时候也许我们加个反射只会让系统降低一点点性能,但架不住成百上千次迭代呀。对于Java反射,一个比较好的解决方案是Code Generate方案,但很多时候Code Generate并不能解决所有反射场景的需求。
-
最后一点不能算是Java的槽点,而是市场导致的,那就是Java技术栈非常卷。咱们东亚人是世界上出了名的卷的,而咱又是特别喜欢在Java上卷的。因此,对于求职面试上,基于Java技术栈的都会要求特别高,网传的面试造火箭工作拧螺丝一点都不为过。面试时被问HashMap的实现还是最常规的,问jvm的几种垃圾回收器实现原理也是家常便饭,更甚的会问jvm源码和字节码。虽然我也遇到和解决过多次jvm层和字节码导致的问题,我也在面试别人时经常问这类问题,但说到底还是因为卷,有那么多应聘者,咱肯定要用更难的问题筛选出最优秀的人,就算工作中一年可能都只用一两次,但遇到的时候,咱不用再教他,他自己也能应用已有知识快速解决问题不是。说到底,还是太卷了。。。
-
-
使用Go后的一些个人感受
使用Go也开发过一些项目了,从Java切换到Go来几乎没有遇到过比较大的问题。以下是一些个人感受:
Go的语法是真的特别简单,一个下午绝对能够上手,但还是有一些语法上的坑,建议在真正做上线项目前多看看一些网传的常见错误
Go本身的基础功能较为完善,从项目创建时的依赖管理,代码格式化到编译器的支持,到最后运行,Go的sdk都能一步到位(还记得多年前那个只装了个jre怎么也把HelloWorld跑不起来的少年)。Go最终编程生成一个二进制可执行文件,可以在相应的操作系统上直接运行,由编译器屏蔽了操作系统的细节。Go对于网络编程也支持的较为完善,从socket到http的支持,都能直接调用sdk的api进行编程。
由于Go在1.8才开始支持泛型,因此Go其实是不支持Java中的一些基本的数据结构的,比如栈、树、堆之类的,虽然这些基本的数据结构都能使用Go的切片轻松实现。由于Go还是面向过程的编程语言,因此其并不支持类和对象,而是以结构体为主,所有的赋值操作都是值传递,虽然也可以使用指针,但相对于Java的面向对象,在一般时候,虽然操作上复杂了,但性能上会有一些优势。
Go的并发编程是比较让人能够津津乐道的,Go不同于Java的系统级线程,Go是以goroutine来进行并发编程的,一般被叫被协程,可以和Java的线程池类比,但goroutine是原生sdk级别支持的,而且sdk还内置了并发的调度,这些调度工作对一般的应用开发透明。同时,Go也在原生sdk层支持了垃圾回收,虽然听说性能不咋滴,但也在渐渐吸收Jvm垃圾回收器的一些优良实现。
目前已有越来越多的公司和项目开始使用Go做一些大型项目的开发,主要还是集中在后端开发这块,特别是在近几年云原生技术越来越火的情况下,Go在大数据和云计算领域中也占有了一席之地,比如云开发一块的k8s和docker就是基于Go语言开发的。而且目前Go语言相对于Java来说还是一门小众编程语言,甚至在使用普及度上还不如python,但其在越来越多的大型项目上被应用,也慢慢证明了其在一些领域内的优越性。咱们在这里不要引入编程语言鄙视链,而是要一直秉承着只有最适合的没有最好的语言。
最后就是国内目的在Go这一块还不是很卷,有一些公司在需求Go技术栈的开发时,面试能够有一些优势,不过,优秀的开发者一定不是拘泥于编程语言的,越往上走,语言就越来越不重要了,重要的是规划、设计与总结能力,以及团队的组织与建设能力。