今天谈一下锁,以及Go里面Sync包里面自带的各种锁,说到锁这个概念,在日常生活中,锁是为了保护一些东西,比如门锁、密码箱锁,可以理解对资源的保护。在编程里面,锁也是为了保护资源,比如说对文件加锁,同一时间只也许一个用户修改,这种锁一般叫作文件锁。
实际开发中,锁又可分为互斥锁(排它锁)、读写锁、共享锁、自旋锁,甚至还有悲观锁、乐观锁这种说法。在Mysql数据库里面锁的应用更多,比如行锁、表锁、间隙锁,有点眼花缭乱。抛开这些概念,在编程领域,锁的本质是为了解决并发情况下对数据资源的访问问题,如果我们不加锁,并发读写一块数据必然会产生问题,如果直接加个互斥锁问题是解决了,但是会严重影响读写性能,所以后面又产生了更复杂的锁机制,在数据安全性和性能之间找到最佳平衡点。
正常来说,只有在并发编程下才会需要锁,比如说多个线程(在Go里面则是协程)同时读写一个文件,下面我以一个文件为例,来解释这几种锁的概念:
如果我们使用互斥锁,那么同一时间只能由一线程去操作(读或写),这就是像是咱们去上厕所,一个坑位同一时间只能蹲一个人,这就是厕所门锁的作用。
如果我们使用读写锁,意味着可以同时有多个线程读取这个文件,但是写的时候不能读,并且只能由一个线程去写。这个锁实际上是互斥锁的改进版,很多时候我们之所以给文件加锁是为了避免你在写的过程中有人读到了脏数据。
如果我们使用共享锁,根据我查到资料,这种叫法大多数是源自MySQL事务里面的锁概念,它意味着只能读数据,并不能修改数据。
如果我们使用自旋锁,则意味着当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
这些锁的机制在Go里面有什么应用呢,下面大家一起看看Go标准库里面sync包提供的一些非常强大的基于锁的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
package main
import "sync"
var once sync.Once
func main() { doOnce() doOnce() doOnce() }
func doOnce() { once.Do(func() { println("one") }) }
|