文章目录
- 一,并发编程
- 1.1,并发和并行的区别
- 1.2,Goroutine
- 1.3,channel
- 1.4,并发安全Lock
- 1.5,WaitGroup
一,并发编程
1.1,并发和并行的区别
并发:
并发,就是通过一种算法将 CPU 资源合理地分配给多个任务,当一个任务执行 I/O 操作时,CPU 可以转而执行其它的任务,等到 I/O 操作完成以后,或者新的任务遇到 I/O 操作时,CPU 再回到原来的任务继续执行。
通过将 CPU 的使用权在恰当的时机分配给不同的任务,使得多个任务在视觉上看起来是一起执行的。CPU 的执行速度极快,多任务切换的时间也极短,用户根本感受不到,所以并发执行看起来才跟真的一样。
总结:
其实并发就是单核cpu不断的切换任务,给我们的感觉像是多个任务同时进行的。
并行:
多核 CPU 的每个核心都可以独立地执行一个任务,而且多个核心之间不会相互干扰。在不同核心上执行的多个任务,是真正地同时运行,这种状态就叫做并行。
一图来区别它们。
1.2,Goroutine
go中使用Goroutine来实现并发concurrently。Go应用程序可以并发运行数千个Goroutines。
func hello(i int) {
println("hello world : " + fmt.Sprint(i))
}
func main() {
for i := 0; i < 5; i++ {
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
如上代码开了五个任务并发执行,输出来看一下。
1.3,channel
Go 语言中的通道(channel)是一种特殊的类型。通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型。
例子:
package main
func main() {
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)
}
}
上述代码解释:
A子协程发生0~9数字到无缓冲通道。
B子协程将传入的数字计算为平方到有缓冲通道。
主协程输出结果如下:
1.4,并发安全Lock
线程安全是指,函数或者某个函数库在多线程的模式被调用时,能够正确处理多个线程之间共享变量,使得程序可以正常运行。
线程调用时线程之间会随时发生切换会发生不可预料的结果,出现线程不安全。
Lock可以在“关键的位置”提供串行特性,保证数据安全与独立
1.5,WaitGroup
Go语言中除了可以使用通道(channel)和互斥锁进行两个并发程序间的同步外,还可以使用等待组进行多个任务的同步,等待组可以保证在并发环境中完成指定数量的任务
WaitGroup 值在内部维护着一个计数,此计数的初始默认值为零。
func hello(i int) {
println("hello world : " + fmt.Sprint(i))
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(j int) {
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()
}
输出来看一下。