Go语言的并发编程
Go语言并发编程
- Goroutine的使用:
在函数或方法调用前面加上关键字go,将会同时运行一个新的Goroutine。
- 在使用子协程时,要确保每个子协程都能正常运行。
因为子协程的异常退出会将异常传播到主协程,会直接导致主协程也跟着挂掉,然后整个程序崩溃了。
- recover是Go语言的一个内建函数,可以让进入宕(dang第四声)机流程中的goroutine恢复过来,recover仅在延迟函数defer中有效。
如果当前的goroutine陷入恐慌,调用recover可以捕获到panic的输入值,并且恢复正常的执行。
- 并发:把任务在不同的时间点交给处理器进行处理。
在同一时间点,goroutine任务并不会同时运行。
并行:把每一个任务分配给每一个处理器独立完成。
在同一时间点,任务一定是同时运行的。
- 创建通道只有一种语法,使用make函数。有两种通道类型:
- 缓冲型通道;var bufferedChannel=make(chan int(类型),1024)
- 非缓冲型通道。var unbufferedChannel=make(chan int)
ch <- x //a send statement x = <-ch //a receive expression in an assignment statement <-ch //a receive statement; result is discarded
- 通道语法<- 一次只能读写一个元素。
通道作为容器,可以像切片一样,使用cap()和len()全局函数来获取容量和元素个数。
- 通道满了,写操作就会阻塞,协程就会进入休眠,直到有其它协程读通道挪出了空间,协程才会被唤醒。如果有多个协程的写操作都阻塞了,一个读操作只会唤醒一个协程。
- Go语言的通道像文件一样,支持读写操作和关闭。
读取一个已经关闭的通道会立即返回通道类型的“零值”。
而写一个已经关闭的通道会抛异常。
如果通道里的元素是整型的,读操作是不能通过返回值来确定通道是否关闭的。
- 使用内置sync包提供的WaitGroup对象,使用计数来等待指定事件完成。(多人写入)
- 非阻塞读写:当select语句所有通道都不可读写时,如果定义了default分支,那就会执行default分支逻辑,这样就起到了不阻塞的效果。
- 竞态检查工具是基于运行时的代码检查,不是通过代码的静态分析来完成的。
这就意味着那些没有机会运行到的代码逻辑中如果存在安全隐患,它是检查不出来的。
需要加上-race来执行,如:go run -race 文件名.go
- sync.Mutex是一个结构体对象,这个对象在使用过程中要避免被复制----浅拷贝。
复制会导致锁被分裂了,也就起不到保护的作用了。
所以在平时的使用中要尽量使用它的指针类型。
- defer语句总是要推迟到函数尾部运行,
所以如果函数逻辑运行时间比较长,会导致锁持有的时间较长,
此刻使用defer语句释放锁未必是一个好主意。
- 在结构体中,外部结构体可以自动继承匿名内部结构体的所有方法。
- sync包除了提供互斥锁Mutex(包括Lock()和Unlock()两个常用方法),
还提供读写锁对象RWMutex
(包括写加锁Lock()、写释放锁Unlock()、读加锁Rlock()以及读释放锁()四个常用方法)。
写锁是排他锁,加写锁时会阻塞其它协程再加读锁和写锁;
读锁是共享锁,加读锁还可以允许其它协程再加读锁,但是会阻塞加写锁。
- sync.Once.Do(f func()),能保证sync.Once块只会执行一次,无论是否更换Once.Do(...)。
1. 线程休眠sleep()(1)sleep(时间)指当前线程阻塞的毫秒数;(2)sleep存在异常InterruptedException;(3)sleep时间达到后线程进入 ...