导图社区 Go语言
Go语言是一个非常有前景的语言,相对于其他语言来说有很多的优势;了解Go语言的开发背景和基础知识;比较全面地总结了Go语言。
编辑于2024-12-22 19:19:18才女笔下的百味人生。李清照以清丽婉约的词风,写尽人间悲欢。她的词作既有"倚门回首,却把青梅嗅"的少女娇憨,也有"帘卷西风,人比黄花瘦"的深闺孤寂。从"误入藕花深处"的闲适到"醒时空对烛花红"的忧思,无不渗透着时节之感与命运波折。这位宋代女词人将闺思、乡愁、国恨揉进词句,用夜雨、残酒、西风等意象,刻画出坎坷人生中的细腻情思,留下穿越时空的生命注脚。
Shell是连接用户与Linux的高效桥梁!作为命令行解释器,Shell无需编译即可执行批处理或交互式命令,支持变量操作和多种运行方式。它既是程序设计语言,也是命令工具,通过echo/printf格式化输出,用export/unset管理变量用户可编写脚本批量执行命令。拥有的逐条交互操作特性包括无数据类型、花括号变量引用及严格命名规则。内置C语言编写的核心,支持大数据挖掘与自动化任务,是Linux生态的基石。
想高效攻克英语?这份学习资源宝典助你从基础到精通! 内容涵盖俞敏洪系列教材,聚焦写作、翻译、语法、词汇、阅读、词典、字帖、词根词缀等内容,提供趣味性的读本,适配全阶段:小学、考研、雅思、托福、专、专八无所不包,可以形成对新东方各种英语学习教材的整体印象,零基础也能系统进阶!
社区模板帮助中心,点此进入>>
才女笔下的百味人生。李清照以清丽婉约的词风,写尽人间悲欢。她的词作既有"倚门回首,却把青梅嗅"的少女娇憨,也有"帘卷西风,人比黄花瘦"的深闺孤寂。从"误入藕花深处"的闲适到"醒时空对烛花红"的忧思,无不渗透着时节之感与命运波折。这位宋代女词人将闺思、乡愁、国恨揉进词句,用夜雨、残酒、西风等意象,刻画出坎坷人生中的细腻情思,留下穿越时空的生命注脚。
Shell是连接用户与Linux的高效桥梁!作为命令行解释器,Shell无需编译即可执行批处理或交互式命令,支持变量操作和多种运行方式。它既是程序设计语言,也是命令工具,通过echo/printf格式化输出,用export/unset管理变量用户可编写脚本批量执行命令。拥有的逐条交互操作特性包括无数据类型、花括号变量引用及严格命名规则。内置C语言编写的核心,支持大数据挖掘与自动化任务,是Linux生态的基石。
想高效攻克英语?这份学习资源宝典助你从基础到精通! 内容涵盖俞敏洪系列教材,聚焦写作、翻译、语法、词汇、阅读、词典、字帖、词根词缀等内容,提供趣味性的读本,适配全阶段:小学、考研、雅思、托福、专、专八无所不包,可以形成对新东方各种英语学习教材的整体印象,零基础也能系统进阶!
Go语言
背景
互联网时代的来临,改变甚至颠覆了很多东西
从前
一台主机就可以搞定一切
现在
互联网时代
后台是由大量分布式系统构成
任何单个后台服务器节点的故障都不会影响整个系统的正常运行
标志着云时代的到来
七牛云
阿里云
腾讯云
在云时代
掌握分布式编程已经成为软件工程师的基本技能
Go语言已经历经十年
最初的追随者也逐渐成长为Go语言的资深用户
Go语言涵盖
基础编程
Web编程
并发编程
内部源码剖析
Go
C
GC
Goroutine
云时代的C语言
在开发效率和运行效率之间取得了绝对的平衡
领域
云计算
云存储
区块链时代
创世纪
最初由谷歌公司的
Robert Griesemer
Ken Thompson
Rob
三位技术大咖
于2007年开始进行设计的
来源于
对超级复杂的C++11特性的吹捧报告的鄙视
目标
设计网络和多核时代的C语言
别称
类C语言
21世纪的语言
继承了C语言
相似的
表达式语法
控制流结构
基础数据类型
调用参数传值
指针
继承和发展了C语言简单直接的暴力编程哲学
你好,世界
所有的Go程序都是由最基本的
函数
用于包含
一系列的语句
执行操作时存放数据的变量
Go语言中对于函数的名字并没有太多的限制
main包中的main()函数默认是每一个可执行程序的入口
package则用于
包装
组织
相关的函数、变量和常量
G语言闭包函数对外部变量是以引用的方式使用的
变量
构成
它们被组织到一个单独的Go源文件中
这些源文件再按照作者的意图组合成合适的package
有机地组成一个完整的Go语言程序
字符串
字符串的内容是不可以改变的
在以字符串为参数传递给
fmt.Println()函数时
字符串的内容并没有被复制
传递的仅是字符串的
地址
长度
Hello World 的革命
G语言移除了语句末尾的分号
数组、字符串和切片
三者之间的关系
在主流的编程语言中数组及其相关的数据结构是使用得最为频繁的,只有在它们不能满足时才会考虑
链表
散列表
可以看作是数组和链表的混合体
更加复杂的自定义数据结构
在底层原始数据有着相同的内存结构
在上层
因为语法的限制而有不同的行为表现
数组
Go语言的数组是一种值类型
虽然数组的元素可以被修改
但是数组本身
赋值
函数传参
都是以整体赋值的方式处理的
定义
一个由固定长度的特定类型元素组成的序列
定义方式
数组的长度明确
数组中的每个元素都以零值初始化
可以在定义的时候顺序指定全部元素的初始化
数组的长度根据初始化元素的数目自动统计
以索引的方式来初始数组的元素
元素的初始化值出现顺序比较随意
特点
一个数组可以由零个或多个元素组成
数组的组成部分
数组的长度
不同长度或不同类型的数据组成的数组是不同的类型
一个数组变量即表示整个数组
可以将数组看成一个特殊的结构体,结构的字段名对应数据的索引,同时结构成员的数目是固定的
内置函数
len()
用于死算数组的长度的
cap()
用于计算数组的容量
返回对应数组的长度
类型
数值数组
字符串数组
结构体数组
函数数组
接口数组
通道数组
空数组
长度为0的数组
用于强调某种特有类型的操作时避免分配额外的内存空间
字符串
Go语言字符串底层数据也是对应的字节数组
字符串的只读属性禁止了在程序中对底层字节数组的元素的修改
字符串赋值
只是复制了
数据地址
对应的长度
不会造成底层数据的赋值
一个字符串是一个不可改变的字节序列
常用来包含人类可读的文本数据
字符串面值常量
UTF8编码
Go语言的源代码要求是UTF8编码
字符串可以包含任意的数据
包括字节值0
结构
字符串指向的底层字节数组
字符串的字节的长度
字符串虽然不是切片,但是支持切片操作
不同位置的切片底层访问的是同一块内存数据
强制类型转换
[]byte
[]rune
每一个转换都隐含重新分配内存的代价
最坏的情况下它们的运算的时间的复杂度都是O(n)
切片
行为非常灵活
它的底层数据对应数据类型的数组
每个切片还有独立
长度
容量信息
切片赋值和函数传递时也是将切片头信息部分按传值方式处理
因为切片头含有底层数据的指针
它的赋值也不会导致底层数据的复制
序列是可以动态增长和收缩的序列
定义
简化版的动态数组
数组的长度是不固定的
切片多了一个Cap成员表示切片指向的内存空间的最大容量
内置函数
len()
用于返回切片容量大小
容量必须大于或者等于切片的长度
操作
添加切片元素
append()
可以在切片的尾部追加N个元素
也可以在开头追加
但是在开头追加一般会导致内存的重新分配,已有的元素全部复制一次
删除切片元素
根据删除元素的位置
从尾部删除
有从开头位置删除
删除开头的元素可以直接移动数据指针
删除开头的元素也可以不移动数据指针,而将后面的数据向开头移动
可以
append()
所谓原地完成
是指在原有切片数据对应的内存区间完成,不会导致内存空间结构的变化
copy()
对于删除中间的元素,需要对剩余的元素进行一次整体挪动,同样可以用append()或copy()原地完成
从中间位置删除
避免切片内存泄露
底层的数组会被保存在内存中,直到它不再被引用。
有时候可能会因为一个小的内存引用而导致底层这个数组处于被使用的状态,这会延迟垃圾回收器对底层数组的回收
函数、方法和接口
函数
对应操作序列
是程序的基本组成元素
类型
匿名
当匿名函数引用了外部作用域中的变量时就成了闭包函数
闭包函数是函数式编程语言的核心
子主题
子主题
子主题
具名
对应于包级的函数
函数是第一类对象
可以将函数保存在变量中
可以有多个参数和多个返回值
参数和返回值都是以传值的方式和被调用者交换数据
支持可变数量的参数
可变数量的参数必须是最后出现的参数
可变数量的参数其实是一个切片类型的参数
方法
绑定到一个具体类型的特殊函数
依托于类型的,必须在编译时静态绑定
特性
面向对象编程
Go语言中的方法是关联到类型的
可以在编译阶段完成方法的静态绑定
方法由函数演变而来
只是将函数的第一个对象参数移动到了函数名前面而已
子类的方法是在运行时动态绑定到对象的
接口
定义了方法的集合
这些方法依托于运行时的接口对象
接口对应的方法是在运行时动态绑定的
它在提供严格的类型检查的同时
通过接口类型实现了对鸭子类型的支持
使得安全动态的编程变得相对容易
对其他类型行为的抽象和概括
独特之处
它是满足隐式实现的鸭子类型
常见的并发模式
Go语言最吸引人的地方是它内建的并发支持
Go语言并发体系的理论是C,A,R GHoare在1978年提出的通信顺序进行
并发并不是并行
并发更关注的是程序设计层面
并发的程序完全是可以顺序执行的,只有在真正的多核CPU上才可能真正地同时运行
并行跟个关注的是程序设计的运行层面
并行一般都是简单的大量从夫
并发编程中最常见的例子就是生产者/消费者模型
该模型主要通过平衡生线程的工作能力来提高程序的整体处理数据的速度
生产者产生一定的数据,然后放到成果队列中,同时消费者从成果队列中来取这些数据
这样就让生产和消费变成了两个异步的两个过程
当成果队列中没有数据时,消费者就进入饥饿的等待中
而当成果队中数据已满时,生产者则面临因产品呢挤压导致CPU被剥夺的问题
发布/订阅模式
简写为
pub/sub模型
在这个模型中,消息生产者成为发布者,而消息消费者则成为订阅者
生产和消费是M:N的关系
在传统生产者/消费者模型中,是将消息发送到一个队列中,而发布/订阅模型则是将消息发布给一个主题
控制并发数
我们需要适当地控制并发的程度
可以给其他的应用/任务让出/预留一定的CPU资源,也可以适当降低功耗缓解电池的压力
赢者为王
并发编程可以简化问题
并发编程可以提高性能
素数筛·
GenerateNatural()函数内部启动一个Goroutine生产序列,返回对应的通道。
然后为每个素数构造一个筛子:将输入序列中是素数倍数的数提出,并返回新的序列,是一个新的通道。
展示了一种优雅的并发程序 结构
因为每个并发体处理的任务粒度太细微,程序整体的性能并不理想
对于细粒度的并发程序,CSP模型中固有的消息传递的代价太高了
并发的安全退出
我们通过close()莱关闭cancel通道.向多个Gorotine广播退出的指令
这个程序仍然不够稳健
当每个Goroutine收到退出指令退出时一般会进行一定的清理工作,但是退出的清理工作不能保证被完成,因为额main线程并没有等待各个工作Goroutine退出工作完成的机制
context包
用来简化对于处理单个请求的多个Goroutine之间与请求域的
数据
超时
退出
子主题
Go语言是带内存自动回收特性的,因此内存一般不会泄露
面向并发的内存模型
背景
在早期,CPU都是以单核的形式顺序执行机器指令
所有的指令都是以串行的方式执行
在相同的时刻有且仅有一个CPU在顺序执行程序的指令
并行编程模型
多线程
从理论上讲,多线程和基于消息的并发编程是等价的
多线程并发模型可以自然对应到多核的处理器,主流的操作系统因此也都提供了系统级的多线程支持
消息传递
Goroutine和系统线程
Goroutine是Go语言特有的并发体,是一种轻量级的线程,由go关键字启动
在真实的Go语言的实现中,Goroutine和系统线程也并不是等价的
尽管两者的区别实际上只是一个量的区别
但正是这个量变引发了Go语言并发编程质的飞跃
每个系统个都会有一个固定大小的栈
这个栈主要用来保存函数递归调用时的参数和局部变量
固定了栈的大小导致了两个问题
对于很多只需要很小的栈空间的线程是一个巨大的浪费
对于少数需要巨大栈空间的线程又面临栈溢出的风险
要么降低固定的栈大小,提升空间的利用率,要么增大栈的大小以允许更深的函数递归调用
这两者是无法兼得的
原子操作
所谓原子操作就是并发编程中最小的且不可并行化的操作
如果多个并发体对同一个共享资源进行的操作是原子的话,那么同一时刻最多只能有一个并发体对该资源进行操作
从线程的角度看
在当前线程修改共享资源期间,其他线程是不能访问该资源的.
原子操作对多线程并发编程模型来说,不会发生有别于单线程的意外情况
共享资源的完整性可以得到保障
顺序一致性内存模型
在Go语言中,同一个Goroutine线程内部,顺序一致性的内存模型是得到保证的.但是不同的Goroutine之间,并不满足顺序一致性的内存模型,需要通过明确定义的同步事件来作为同步的参数.
如果两个事件不可排序,那么就说这两个事件是并发的
初始化顺序
Go程序的初始化和执行是从main.main()函数开始的
如果mian包里导入了其他的包,则会按照顺序将它们包含到main包里
Goroutine的创建
基于通道的通信
通道
是在Goroutine之间进行同步的主要方法
不靠谱的同步
严谨的并发程序的正确性不应该是依赖于CPU的执行速度和休眠时间等不靠谱的因素的
严谨的并发也应该是可以静态推导出结果的
根据线程内顺序一致性,结合通道或sync事件的可排序性来推导。最终完成各个县城各段代码的偏序关系排序
如果两个事件无法根据此规则来排序,那么它们就是并发的,也就是执行先后的顺序不可靠的
解决同步问题的思路是相同的
使用显示的同步