go语言的并发 | 青训营笔记

191 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记。本笔记主要记录go语言在实际开发中的优势与go语言性能强大快速的原因。

1.并发vs并行

从多线程运行的角度上看,

  • 并发是指多线程程序在单核cpu上的运行
  • 并行是指多线程程序在多核cpu上的运行

src=http___pic4.zhimg.com_v2-775825b88d3a808a33530934c9aab993_r.jpg&refer=http___pic4.zhimg.webp

go语言实现了并发调度极高的模型,通过高效的调度,可以最大限度利用计算资源发挥多核优势,可以说go语言就是为并发而生的。

2.协程

为了实现高效率的并发运行,在go语言里需要用到协程(goroutine)。协程往往与线程一起理解。

  • 线程相比于协程,属于一种比较昂贵的系统资源,属于内核态。它的创建,切换,停止都属于很重的系统操作,需要耗费大量计算资源。它的栈内存属于MB级别。
  • 协程更像是轻量级的线程,属于用户态。在go语言内部即可完成对协程的创建和调度。线程可以运行多个协程。它的栈内存属于KB级别。

3.goroutine

快速输出,不要求顺序->需要使用多次协程

package concurrence

import (
	"fmt"
	"time"
)

func hello(i int) {
	println("hello goroutine : " + fmt.Sprint(i))
}

func HelloGoRoutine() {
	for i := 0; i < 5; i++ {
		go func(j int) {//在调用函数时在函数前加一个go的关键字即可创建协程
			hello(j)
		}(i)
	}
	time.Sleep(time.Second)
}

4.channel与sync

对于go语言而言,一般通过通信共享内存。go程序内部为若干协程,协程的通信方式大多以使用线程间通信实现。

  • channel是一个用来传递数据的数据结构,可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯,利用“<- ”指定通道的方向,发送或接收。
package concurrence

func CalSquare() {
	src := make(chan int)//创建无缓冲通道的channel
	dest := make(chan int, 3)//创建有缓冲通道的channel
	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)
	}
}
  • sync(锁)可以进行多个任务同步,避免竞态的发生,保证并发环境中的任务完成。
package concurrence

import (
	"sync"
	"time"
)

var (
	x    int64
	lock sync.Mutex
)

func addWithLock() {
	for i := 0; i < 2000; i++ {
		lock.Lock()
		x += 1
		lock.Unlock()
	}
}
func addWithoutLock() {
	for i := 0; i < 2000; i++ {
		x += 1
	}
}

func Add() {
	x = 0
	for i := 0; i < 5; i++ {
		go addWithoutLock()
	}
	time.Sleep(time.Second)
	println("WithoutLock:", x)
	x = 0
	for i := 0; i < 5; i++ {
		go addWithLock()
	}
	time.Sleep(time.Second)
	println("WithLock:", x)
}

func ManyGoWait() {
	var wg sync.WaitGroup
	wg.Add(5)
	for i := 0; i < 5; i++ {
		go func(j int) {
			defer wg.Done()
			hello(j)
		}(i)
	}
	wg.Wait()
}

总结

go语言的并发在实际开发中在速度方面非常有优势,但由于并发无顺序可言,还需要与其他功能一起使用才能达到目的。

参考资料: