2022年9月

进程

进程是系统分配资源和调度的基本单位。一个应用程序为1个进程。地址独立。

内存管理

进程在内存主要分为5个区:
1.代码区 (.text) - 存放函数体的二进制代码
2.文字常量区 (.rodata) - 存放常量字符串
3.静态区 (static) - 存放全局变量、静态变量
4.堆区 (heap) - 开发者手动分配的内存空间,结构类似链表
5.栈去 (stack) - 存放函数参数、局部变量。由编译器自动管理,结构类似栈。

线程

线程是cpu调度的最小单位,一个进程内的线程间资源共享。
线程是由系统内核提供的服务,用户通过系统调用让内核启动线程,内核负责线程的调用和切换。

协程

协程是go自己管理的线程,比系统线程开销更少,速度更快。

1.context
2.channel
3.map
4.gmp模型
5.用多个协程交替打印abc
6.多个协程交替打印字符串和数字数组,直到字符串结束。
7.gin.Context
8.协程调度和线程有什么区别
9.sync.Map
10.sync.Mutex
11.sync.RwMutex
12.sync.WaitGroup
13.gc原理

1.context

Context可以控制一组树状结构的goroutine,相比于waitgroup,Context对派生的goroutine比waitgroup有着更强的控制能力。waitgroup适用于确定数量的goroutine,未知数量的goroutine,可采用context控制并发。Context可设置父子关系,父关闭,子也关闭。同时支持延时关闭和超时关闭。

2.channel

channel(通道)是go自带的、且唯一一个并发安全的类型。
一个通道相当于一个FIFO队列。

注意事项

1.向一个已关闭的通道发送操作,会引发panic。
2.试图关闭一个已经关闭的通道也会引发panic。

7.gin

8.协程、线程

9.sync.Map

引入原因

map类型不是并发安全的,并发读写会报fatal error

fatal error: concurrent map read and map write

case:

var testMap  = map[string]string{}
func main() {
   go func() {
      for{
         _ = testMap["bar"]
      }
   }()
   go func() {
      for  {
         testMap["bar"] = "foo"
      }
   }()
   select{}
}

map为何会出现并发异常

go通过flags的hashWriting字段来检测map是否并发异常。
查询操作
flags.hashWriting > 0,则抛出异常。
写操作
1.写入前检查一次标记位,通过后打上标记
2.写入完成后再检查标记位,通过后再打上标记


   //各类前置操作
   ....
   if h.flags&hashWriting != 0 {
      //检查是否存在并发
      throw("concurrent map writes")
   }

   //赋值标记位
   h.flags ^= hashWriting
   ....
   //后续操作
  done:
   //完成修改后,再次检查标记位
   if h.flags&hashWriting == 0 {
      throw("concurrent map writes")
   }
   //还原标记位取消hashWriting标记
   h.flags &^= hashWriting

如何解决map并发问题

1.使用sync.RwMutex

type cocurrentMap = struct {
   sync.RWMutex
   m map[string]string
}

func main() {
   var testMap = &cocurrentMap{m:make(map[string]string)}
   //写
   testMap.Lock()
   testMap.m["a"] = "foo"
   testMap.Unlock()
   //读
   testMap.RLock()
   fmt.Println(testMap.m["a"])
   testMap.RUnlock()
}

由于锁开销较大,对并发量有影响,所以推荐使用sync.Map

2.sync.Map

sync.Map的实现

空间换时间思想,同时维护两份数据,readonly&dirty,read用来避免读写冲突。
结构如下:

type Map struct {
   mu Mutex //锁
   read atomic.Value //readOnly
   dirty map[interface{}]*entry //*entry
   misses int
}

type readOnly struct {
   m       map[interface{}]*entry
   amended bool // true if the dirty map contains some key not in m.
}

type entry struct {
   p unsafe.Pointer // *interface{}
}

case:

var m sync.Map
//write
m.Store("test", 1)
m.Store(1, true)

//read
val1, _ := m.Load("test")
val2, _ := m.Load(1)
fmt.Println(val1.(int))
fmt.Println(val2.(bool))

//遍历
m.Range(func(key, value interface{}) bool {
   //....
   return true
})

//删除
m.Delete("test")

//读取或写入
m.LoadOrStore("test", 1)

10.sync.Mutex


11.sync.RwMutex


12.sync.WaitGroup


13.GC原理

转自 https://mp.weixin.qq.com/s/niLk_n9Yp-iyl_RIie3Umw

最长回文子串

反转链表

x3

括号生成

top K

x2

合并链表

岛屿数量

最大子序列和

x2

有序数组转二叉搜索树

二叉树层序遍历

反转二叉树

是否是有效括号

找出两个有序数组的相同元素

最长公共前缀

x2

整数反转

判断链表是否有环