笔记篇:工程实践| 青训营
并行与并发
- 并发(Concurrency)是指在单个处理器上同时执行多个任务的能力。它是通过在时间上交替执行任务,使得每个任务都有机会向前推进。在并发中,任务之间相互独立,每个任务按照自己的节奏执行,但它们之间会交替执行。使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的。
- 并行(Parallelism)指在同一时刻,有多条指令在多个处理器上同时执行。
- 并发是一个人同时吃三个馒头,而并行是三个人同时吃三个馒头。
- 并行在多处理器系统中存在,而并发可以在单处理器和多处理器系统中都存在,并发是并行的假象,并行可以认为实现并发的手段。
计算机的"大脑"。
- 在计算机领域中,处理器和CPU(Central Processing Unit)通常可以互换使用。它们都指代计算机的中央处理器部件,负责执行指令和进行计算。
- 处理器可以是单核或多核的,分别支持并发执行和并行处理。
- 每个核心都是一个独立的处理单元,每个核心都包含算术逻辑单元(ALU)、寄存器、高速缓存等,它可以执行指令和进行数据处理。
进程、线程、协程
-
进程(Process):进程是操作系统分配资源和管理程序执行的基本单位。进程之间是相互独立的,拥有独立的内存空间,可以同时运行多个进程,实现多任务操作。进程间通信需要使用额外的机制,如共享内存、管道等。
-
线程(Thread):线程是进程中执行任务的最小单位。程共享进程的内存空间和上下文,可以同时执行多个线程,实现多线程并发操作。线程之间可以直接通信和共享数据。
-
协程(Coroutine):协程是一种用户态的轻量级线程,它并不是由操作系统内核来管理和调度,而是由程序员控制其执行和切换的时机。可以在同一个线程内实现多个协程的切换,实现并发和并行操作。
Go
并发
Go
中的多线程编程称为goroutine,目前统一译为协程。因为协程kb级别,轻量很多,一次可以创建上万个协程,这也就是Go
语言更适合高并发场景的原因。- go 的并发编程采用的 CSP (Communicating Sequential Process) 模型,主要基于协程 goroutine 和通道 channel。
- 在函数中调用了休眠(
sleep
)函数,这个函数就会告诉Go
调度器去调度其他可被调度的Go
协程。- 调度器(Scheduler)是操作系统或者编程语言运行时系统的一部分,负责协调和管理多个任务或线程的执行顺序和分配计算资源。
- 在
Go
语言中,调度器(Goroutine Scheduler)是运行时系统的一部分,负责调度和管理Goroutine的执行。它使用了一种称为“抢占式的协作式调度(Preemptive Cooperative Scheduling)”的方式,即允许Goroutine主动让出执行权,也可以被强制抢占执行权,以确保公平性和避免资源竞争。- 只有非休眠(non-sleeping
)的Go
协程才会被认为是可被调度的。
Channel
- src 是源代码(Source Code)的缩写,通常用于指代源代码文件或源代码目录。
- go语言提供的消息通信机制称为channel,
go
语言在设计上强调不要通过共享内存来通信,而应该通过通信来共享内存,但实际都有存在呢。 - Go语言中的channel有三种基本操作:发送、接收、关闭。
- 关闭一个channel之后,就不能再向它发送数据了,但是仍然可以从它接收数据。
- 阻塞式机制:当一个协程向一个channel发送数据时,如果channel已经满了,发送操作会被阻塞,直到有其他协程从channel中取走了数据。同样地,当一个协程从一个channel中接收数据时,如果channel中没有数据可供接收,接收操作会被阻塞,直到有其他协程向channel中发送了数据。这种阻塞式的机制可以保证协程之间的同步和通信。
- 容量 :无缓冲channel的容量为0,意味着它不能存储任何数据,数据发送者必须等待数据接收者接收数据后才能继续发送。有缓冲channel的容量大于0,可以存储一定数量的数据,只有当缓冲区满时,发送操作才会阻塞。
- 在
Go
语言中,通过在函数或方法后面使用一对括号,可以直接调用该函数或方法。
import (
"fmt"
)
func printhello() {
fmt.Println("hello world")
}
func main() { // 声明 main 主函数
fmt.Println("Hello")
go printhello()
fmt.Println("world")
}
func CalSquare() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer cLose(src )
for i:=0;i<10;i++{
src <- i
}
}()
go func() {
defer cLose(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
println(i)
}
依赖管理
- 依赖包和SDK类似,都是指向提供特定功能的软件工具或库。
- 对于依赖包的管理经历了
GOPATH,GO VENDOR, GO MODULE
(由于对于sdk包版本的兼容控制)
- 依赖分发proxy的模式---缓存的模式 具有相同思想,学下去。