golang并发知识点总结
1. go申明 goroutine,也可以申明匿名函数,就表示开启多协程并发访问
2. go多个goroutine通信,使用channel,必须用 info:=make(chan string) 格式定义,即用make关键字
3. go申明的并发访问方法,要考虑多个协程同时执行对公共资源的占用和读写,如磁盘读写,网络访问,数据库访问等,下面例子体现并发访问导致的“事务不一致”问题,以及解决方法
4. golang 加锁机制非常轻量简洁 。
go 共享锁定义 mutex := &sync.Mutex{} 传递锁的指针,要注意多个协程要用一个共享锁,传入不同的锁,不能达到加锁的功能。
实例看懂并发和锁
const (
openLock = true
)
func main2() {
gfile.PutContents("content.txt", "")
concurrency()
chuan()
}
func chuan() {
gproc.StartTime()
// 串行 访问十次 非并发,每次协程id不变
for i := 0; i < 10; i++ {
info := goMethod1("串行", nil)
glog.Debug(info)
}
glog.Info("串行访问十次结束,耗时:", gproc.Uptime())
}
func concurrency() {
//取锁地址
mutex := &sync.Mutex{}
gproc.StartTime()
//并发访问十次
//info:=make(chan string)
for i := 0; i < 10; i++ {
//传递共享锁指针
go goMethod1("并行", mutex)
}
glog.Info("并发访问十次结束,耗时:", gproc.Uptime())
}
//这里的锁是来自上层主线程的共享锁
func goMethod1(mtype string, mutex *sync.Mutex) string {
if mutex != nil && openLock {
mutex.Lock()
defer mutex.Unlock()
}
info := mtype + "访问协程id:" + (strconv.FormatUint(GetGoroutineID(), 10)) + "\r\n"
gutil.TryCatch(func() {
//故意写入两次体验锁机制保证每一个协程事务一致,锁机制
gfile.PutContentsAppend("content.txt", info)
gfile.PutContentsAppend("content.txt", info)
}, func( exception interface{}) {
glog.Error(exception)
})
return info
}
func GetGoroutineID() uint64 {
b := make([] byte , 64)
runtime .Stack(b, false)
b = bytes .TrimPrefix(b, []byte("goroutine "))
b = b[:bytes.IndexByte(b, ' ')]
n, _ := strconv.ParseUint(string(b), 10, 64)
return n
}
结果分析
上面代码执行两种结果如图所示。
不加锁文件内容:方法写入的两句话没法连续写入文件。
加锁以后文件内容:方法写入的两句话连续写入文件。
有锁,就可以保障方法对共享资源的“事务一致性”。