为什么需要一门新的语言

语言分类为编译型语言(C, c++, Java,C#,objective-c等)和动态解析型语言(PHP,Python,Ruby,lua,javaScript等);

语言最早的历史:C是最面向汇编代码的,原则上每一行C代码都可以精准的映射到汇编指令上,因此对于操作系统底层的操控来看最为精准。而C++是在C之上发展起来的面向对象语言,所以说兼顾了对系统底层最精准的把控和一些面向对象的理念;

   编程哲学和语言特性:c++,java等系统语言根本编程哲学为面向对象(衍生多种流派),所以在设计模式上适合大型系统的开发,而另一大编程哲学则是简单;C和c++:贴近底层操作精准,最为重要的为指针的概念,使其对内存的操作可以精准完成,但是指针用好了是神器,用差了是垃圾,所以非常完善的测试框架对于语言高级特性的把握,十分关键。否则大型项目内存泄漏和崩溃漏洞遍地都是。新型开发语言如果不是面向对象,则设计模式不适合大型复杂系统开发,如果没有指针等概念,则使其对内存的精准操作变得不可能完成;而其他的特性还包括了 静态的,强类型的.动态解析型语言:简单

性能不是问题,python有一个很大的libs生态系统,最终用来粘合代码;

   Go语言的编程哲学:

  1. 并行与分布式的支持。多核化和集群化是互联网时代的主要特征。
  2. 软件工程支持。工程规模不断扩大是产业发展的必然趋势
  3. 编程哲学重塑:足够简单

语言特性

并发与分布式

  并发与分布式编程体现在物理层面便是多核与集群化;进程线程协程都抽象为执行体的概念,区别为:进程是系统进行资源分配和调度的基本单位,是操作系统的基础,进程是程序的实体,是一个具有独立功能的程序关于某个数据集合的一次运行活动,他可以申请和拥有系统资源是一个动态的概念一个活动的实体。线程是进程内一个相对独立的,可调度的执行单元,是系统独立调度和分配CPU的基本单位,切换由CPU时间片调度算法分配,不受自己控制;而协程其切换由自己控制,也就是由当前协程切换到其他协程由当前协程控制;

  时间片很小,所以看到的线程处理的很快算作为了并发,但核数与线程数一致才算做并发,网络通信和本地读写都会阻塞并发执行;GO在语言支持协程,关键字go,语言标准库提供了所有系统调用操作(syscall),当然也包括了同步IO操作;

  执行体之间的通信: 1.互斥和同步 2.消息传递  并发编程模型也就有了两种:共享内存模型和消息传递模型(依赖于类似消息队列或者进程邮箱的方式),golang采用了消息传递模型,其消息对立叫做通道

软件工程

工程规模的扩大,多数软件需要一个团队去完成,团队协作过程中,规范化提现在各个层面:代码风格规范,错误处理规范,包管理,契约规范,单元测试规范,功能开发的流程规范

Golang是第一个将代码风格强制统一的语言和首创的错误处理规范

编程哲学

 多种流派:面向过程,面向对象,函数式,面向消息;golang 如果一个特性并不对解决任何问题有显著的价值,那么go就不提供它。非侵入式接口特性。

保留在看

 

go语言特性(静态类型语言)

  1. 自动垃圾回收

所有的内存分配动作都会在运行时被记录,同时任何对该内存的使用也都会被记录,然后垃圾回收器会对所有已经分配的内存进行跟踪监测,一旦有些内存已经不在被任何人使用,就阶段性的回收这些没人用的内存。

  1. 更丰富的内置类型

除了常用的其他静态语言支持的简单内置类型外,golang支持字典类型map 和数组切片Slice(可动态增长的数组);

  1. 函数多返回值

可以用下划线作为占位符忽略不关心的返回值

  1. 错误处理

Defer关键字用于标准的错误处理流程

  1. 匿名函数和闭包

Go语言中所有的都是值传递

  1. 类型和接口

Go语言的类型定义非常接近C语言中的struct,直接沿用了struct关键字,没有沿袭C++和java的传统去设计一个超级复杂的类型系统,只支持最基本的类型组合功能;

以前实现接口前必须定义该接口,且将类型和接口紧密绑定;go语言支持非侵入式的接口,在用的时候再去转换;

  1. 并发编程

Go语言使用了协程goroutine而不是裸用操作系统的并发机制,以及使用消息传递来共享内存而不是使用共享内存来通信,实现CSP通信顺序进程模型来作为goroutine间的通信方式。Go语言用channel通道了来轻巧的实现CSP模型

  1. 反射

反射可以获取对象的详细信息,并可动态操作对象。反射最常见的使用场景是做对象的序列化;

Java中Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。核心就是先得到代表的字节码的Class,Class类用于表示.class文件

  1. 语言交互性

Cgo即是语言特性也是工具名称

 

Go工程管理

包是go语言里最基本的分发单位,也是工程管理中依赖关系的提现;要生成GO可执行程序,必须建立一个名字为main的包,并且包含一个叫main()的函数;且不要求分号结尾

Go的编译环境,默认安装在/usr/local/go目录下;go run 编译 链接 运行 合为一步;没有任何中间文件和可执行文件,go build  生成可执行文件;6g 61才是真正的编译器和链接器,go 是明令行工具

工程管理,go test 单元测试

打印日志 和GDB调试器

Go顺序编程

变量:本质就是申请一块数据存储空间

关键字 var,但在初始化时关键字不再是必要元素  :=

常量:编译期间就已知不可改变的值

无类型常量。关键字 const,大写字母开头的常量包外可见,小写则为包内私有

类型,go语言都是值传递,而java是份基础类型和引用类型

基础类型:

  1. 布尔 bool
  2. 整型 int8/byte/int16/int/uint/unitptr
  3. 浮点类型 float32/float64   不是精确的表达式,不推荐用==
  4. 复数类型 complex64/complex128  实部real 与虚部imag
  5. 字符串string  C/C++不存在原生的字符串类型  go语言仅支持UTF-8 和Unicode编码
  6. 字符类型 rune  一个是byte(时间是uint8的别名)代表utf-8的单个字节的值,rune代表单个unicode字符
  7. 错误类型 error

复合类型:

  1. 指针 pointer
  2. 数组array  值类型
  3. 切片slice  一个指向原生数组的指针,数组切片中的元素个数,数据切片已分配的内存空间
  4. 字典map
  5. 通道chan
  6. 结构体struct
  7. 接口 interface

流程控制

  1. 条件语句

不允许包含return

  1. 选择语句

Fallthrough关键字,才会继续执行紧跟的下一个case

  1. 循环语句

只支持for关键字,不支持逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多个变量,break 支持更高级的层次控制

  1. 跳转语句

Goto 跳转到本函数内的某个标签

函数

小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用

不定参数  …interface{} 本质是数组切片

多返回值

匿名函数和闭包(包含自由变量的代码块,要执行的代码块为自由变量提供绑定的计算环境)自由变量=未绑定到特定对象;闭包的价值在于可以作为函数对象或者匿名函数;闭包的实现确保只要闭包还在使用,被闭包引用的变量就会一直存在;

错误处理

Error类型,实际是接口

Defer语句遵循先进后出的原则

Panic() 错误处理流程, recover()终止错误处理流程

 

Go面向对象编程

整个类型系统通过接口串联,浑然一体

类型系统:类型系统才是一门编程语言的地基,一个语言的类型体系结构;

  1. 基础类型
  2. 复合类型
  3. 可以指向任何对象的类型(any类型)
  4. 值语义和引用语义
  5. 面向对象:即所有具备面向对象特征的类型
  6. 接口

Java中存在两套完全独立的类型系统,一套是值类型系统,主要是基本类型基于值语义;一套以objec类型为根的对象类型系统,基于引用语义;相比之下go语言大多数类型为值语义,any类型为interface{};

  1. 为类型添加方法 (其他语言隐藏了第一个参数)

C++的面向对象让人迷惑的原因就在于其隐藏的this指针,一旦显露,大家看到的就是面向过程编程;而对于go语言来说

方法施加的目标(对象)显示传递,没有被隐藏起来

方法施加的目标(对象)不需要非得是指针,也不用非得叫this ,但是风险就是值传递和引用传递

  1. 值语义和引用语义

引用类型:切片,map,channel,接口   本质上是指针

  1. 结构体

Go语言中的结构体和其他语言的类有同等地位;go不支持继承在内的大量面向对象的特性,只保留的组合最基础的特性。组合只是复合类型的基础;go语言除了指针类型都可以定义自己的方法,所以结构体只是很普通的复合类型;

  1. 初始化

一般通过全局的创建函数来完成;

  1. 匿名组合(变向实现了继承):特点:虚基类

被组合的类型所包含的方法都升级成了这个组合类型的方法,但其实他们被组合方法调用时接收者并没有改变;

匿名组合类型相当于以其类型名称(去掉包名)作为成员变量的名字

  1. 可见性(访问性是包一级的,大小写)
  2. 接口:契约-公共特性的抽象(需求方和实现方)

侵入式接口:实现类需要明确声明自己实现了某个接口;

非侵入式接口:一个类只要实现了接口所要求的所有函数,我们就说该类实现了这个接口

接口赋值:对象实例赋值给接口(go在方法添加时不要求对象非得是指针,但在实例赋值给接口时会根据值传递的来生成一个指针的方法),将一个接口赋值给另一个接口(子集)

接口查询:

类型查询:type

接口组合:

  1. Any类型:空接口 inter{}

Go并发编程

并发意味着程序在运行时有多个执行上下文,对应着多个调用栈;每一个进程在运行时都有自己的调用栈和堆,有一个完整的上下文,操作系统在调度进程时,会保存被调度进程的上下文环境,等到进程获得时间片后,在恢复该进程的上下文到系统中。

多进程:操作系统层面进行并发的基本模式,也是开销最大的模式(因为所有的进程都是内核管理的)

多线程:依然属于系统层面的并发模式,但开销小很多;

基于回调的非阻塞/异步IO:多线程会很快耗尽系统的CPU和内存资源,通过事件驱动的方式使用异步IO,使服务器持续运转,并且尽可能的少用线程;

协程:本质上是一种用户态线程,不需要操作系统来进行抢占式调度,且在真正的实现中寄存于线程。最大的优点在于轻量级,可以轻松创建上百万个而不会导致资源枯竭,而线程和进程最多也不会超过1W个;go语言标准库提供的所有系统调用操作都会让出CPU给其他gorountine;(充分利用了CPU与其他硬件设备固有的异步性)

并发编程的难度在于协调,而协调就要通过交流,所以并发单元间的通信是最大的问题了;(共享数据和消息)线程之间通信只能采用共享内存的方式

消息传递系统:对线程间共享状态的各种操作都被封装在线程之间传递的消息中;发送消息时对状态进行复制(开销大),在消息传递的边界上交出这个状态的所有权。

Channel是语言级别提供的gorountine间的通信方式,channel是进程内的通信方式,如果需要跨进程通信,建议用分布式系统的方法来解决,比如SOCKET或者http等通信协议,channel是类型相关的;

Select  限制 case 语句里面必须是一个channel操作,而且可以实现超时机制

缓冲机制:创建channel时规定缓冲区大小;

Channel 本身也是原生类型,本身可传递的特性从而实现unix管道特性;

单向channel只能用于发送和接收数据,这其实只是一种使用限制;从设计的角度来看,代码都应该遵循最小权限原则,其中使用又借用了类型转换

多核并行化,go编译器还不能很智能的去发现和利用多核优势,实际创建的gorountien都运行在一个CPU核心上,在一个goroutine得到时间片的时候,其他goroutine都会处于等待状态,所以可以通过设置环境变量GOMAXPROCS的值来控制使用多少个CPU核心;

出让时间片:gosched()

虽然利用channel进行通信,但是不可避免的会存在多个goroutine之间共享数据,所以提供了同步锁;

全局唯一性操作:once`

Go网络编程

Go安全编程

Go进阶

反射

Type 和value  (reflect包)

语言交互性

支持c语言

链接符号

Gdb

Gorountine机理(协程机理)

协程的特点:

  1. 能够在单一的系统线程中模拟多个任务的并发执行
  2. 在一个特定时间只有一个任务运行,即并非真正的并行
  3. 被动的任务调度方式,即任务没有主动抢占时间片的说法。当一个任务正在执行时,外部没有办法终止它。要进行任务切换,只能通过自身主动让出CPU使用权
  4. 每个协程都有自己的堆栈和局部变量
  5. 每个协程的3种状态:挂起,运行和停止

协程库:

  1. 任务及任务管理
  2. 任务调度器
  3. 异步IO
  4. Channel

Channel

  1. 内存缓存,用于存放元素
  2. 发送队列
  3. 接受队列

接口机理