这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
一、并发
并发指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且都在同一个处理机上运行,但任一个时刻上只有一个程序在单处理机上运行。
并行指一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行。
Go(又称 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态强类型、编译型语言。Go 语言语法与 C 相近,但功能上有:内存安全,GC(垃圾回收),结构形态及 CSP-style 并发计算。
1.协程
- 协程比线程更小,十几个协程体现在底层相当于五六个线程。
- 协程的创建只需要在函数前加一个
go即可。 - Go在main的主线程内创建多个协程,但是主线程不会等待协程执行完毕。
- 一旦主线程执行完毕,被创建的协程没被执行就被“抛弃”了。
- NewTimer与NewTicker
//NewTimer会在指定的时间间隔后创建一个发送当前时间的新的计时器timer
time1 := time.NewTimer(time.Second * 2)
//NewTicker创建一个定时器,每秒钟执行一次
ticker := time.NewTicker(time.Second * 1)
2.同步协程
1.WaitGroup
Go语言的同步通过sync.WaitGroup来实现,WaitGroup实现了一个类似队列的结构,可以一直向队列添加任务。
- Add:添加或者减少等待协程的数量。
- Done:相当于Add(-1)。
- Wait:执行阻塞,直到所有的WaitGroup数量变成0。
2.Cond
Cond的使用非常简单,只需要借助于lock实现线程阻塞。Cond只定义了三个方法:Wait()、Signal()和Broadcast()。
Signal函数负责通知已经获取锁的协程解除阻塞状态开始正常运行,但Signal只能通知随机一个获取到锁的协程,可以使用Broadcast通知所有协程全部解除阻塞状态。
3.Once
对于从全局角度只需要运行一次的代码,比如全局初始化操作,Go语言提供了一个once类来保证全局的唯一性操作。
3.通道
通道是Go语言在语言级别提供的协程间的通信方式,通过使用通道可以在两个或者多个协程之间传递消息。
1.通道定义
通道是类型相关的,一个通道只能传递一种类型的值,这个类型需要在声明通道时指定。如果通道没有被初始化,那么它的值为nil。
通道是一种先进先出的结构(队列),他保留了发送到通道中的资源的顺序。
通道是一种引用类型,需要用make函数为其分配内存。
var ch1 chan string
ch1 = make(chan string)
//或者简写为
ch1 := make(chan string)
操作符<-表示数据的传递方向
- ch <- int1:变量int1被发送到通道ch中;
- int2=<-ch:变量int2从通道ch接收数据;
- <-ch:读取通道顶部的值。
2.通道的缓冲机制
通道的发送/接收操作在对方准备好之前是线程阻塞的。
通道的缓冲区在未满之前,可以反复向通道发送或读取消息;缓冲区满后,如果继续向该通道发送消息会造成程序死锁。
//带缓冲的通道的初始化
ch := make(chan type, value)
3.通道的close
只有需要告诉接收者没有新的数据时才需要关闭通道,所以只有发送者才可以关闭通道。
- 关闭一个未初始化(nil)的通道会产生错误(panic)。
- 重复关闭同一个通道会产生错误(panic)。
- 向一个已关闭的通道中发送消息会产生错误(panic)。
- 从已关闭的通道读取消息不会产生错误(panic),且能读出通道中还未被读取的消息,若消息均已读出,则会读到类型的零值。
- 从一个已关闭的通道读取消息永远不会阻塞,并且会返回一个为false的bool类型的变量,可以用来判断通道是否成功关闭。
4.select
select是Go语言的一个控制结构,类似于switch,用于处理异步IO操作。
select会监听case语句通道的读写操作,当case读写操作为非阻塞状态,将触发相应的动作。
- 如果多个case可以运行,select会随机公平地挑选一个执行,其他的均不会执行。
- 如果没有可运行的case,且有default,那么执行default。
- 如果没有可运行的case,且没有default,那么select将阻塞,直到某个case通信可以运行。
Go语言不会让select长时间地阻塞下去,可以设置一个select的超时判断来让select提前终止,而不必继续等待通道的操作。
二、文件操作
输入输出操作使用原语(由若干条指令组成,用于完成一定功能的一个过程)实现的,这些原语将数据模拟成可读或可写的字节流。
1.写数据到文件
io包的io.Write表示一个编写器,它从缓冲区读取数据,并将数据写入目标资源。
//第一个值是写入的字节数,第二个值是error错误值
type Writer interface{
Write(p[]byte)(n int,err error)
}
实现了Write接口的对象有os.stdout、os.stderr、os.file等。
2.从文件中读取数据
- 创建文件
func Create(name string)(file *File,err error)Create函数采用模式0666(任何人都可读写,不可执行)创建名为name的文件,如果文件已存在,就截断它(为空文件)。如果成功,则返回的文件对象可用于I/O;对应的文件描述符具有O_RDWR模式。如果出错,错误底层类型是*PathError。 - 打开文件
func Open(name string)(file *File,err error)Open函数打开一个文件用于读取,操作成功返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。 - 打开文件
func OpenFile(name string,flag int,perm FileMode)(file *File,err error)OpenFile是更一般性的文件打开函数,它会使用指定的选项、指定的模式打开指定名称的文件。如果成功,则返回的文件对象可用于I/O;如果出错,错误底层类型是*PathError。 - 读文件
type Reader interface{ Read(p[]byte)(n int,err error) }实现了Write接口的对象有os.stdin、os.file等。 四条规则
3.文件的复制
func Copy(dst Writer,src Reader)(written int64,err error)实现从源到目标文件的复制,直到读到源的EOF或者其他错误,它返回的所复制的字节数及复制过程出现的第一个错误。 记得打开第一个文件做了错误判断后要紧跟一个defer close延迟调用。func CopyN(dst Writer,src Reader,n int64)(written int64,err error)从源文件复制n字节(或者遇到错误中断)到目标文件,并返回实际复制的字节数。- 将原文件的内容读出来,再写到另一个文件中去,完成文件的复制。