Go 协程(绿程/轻量级线程 用户态)--没有历史包袱
协程
初识
GMP
python 的单个协程占用 内存少
import asyncio
async def p(n : int) -> None:
print(n)
await asyncio.sleep(1)
async def main():
for i in range(1000):
asyncio.create_task(p(i))
await asyncio.sleep(30)
if __name__ == '__main__':
asyncio.run(main())
go 的 协程 写起来简单
package main
import (
"fmt"
"sync"
)
// Add 的数量与 Done 的数量必须相等
func main(){
wg := sync.WaitGroup{}
for i:=0; i<100; i++{
wg.Add(1)
go func(i int){
defer wg.Done()
fmt.Printf("current i: %v \n", i)
}(i)
}
wg.Wait()
}
go 中的锁
package main
import "fmt"
func add100(cnt *int) {
for i := 0; i < 100; i++ {
*cnt += 1
}
}
func sub100(cnt *int){
for i:= 0; i<100; i++{
*cnt -= 1
}
}
func main(){
// 因为是同步代码,所以此处不会造成最后数据不对,稍后我们改为协程
var cnt = 0
add100(&cnt)
// 此处加到 100 了
fmt.Println(cnt)
sub100(&cnt)
// 此处减到 0 了
fmt.Println(cnt)
}
----========= 下面为协程代码, 因为出现共享数据 因为非原子性操作会造成数据不一致 ==========--------
package main
import (
"fmt"
"sync"
)
func add100(cnt *int) {
defer wg.Done()
for i := 0; i < 100000; i++ {
*cnt += 1
}
}
func sub100(cnt *int){
defer wg.Done()
for i:= 0; i<100000; i++{
*cnt -= 1
}
}
var wg = sync.WaitGroup{}
func main(){
wg.Add(2)
var cnt = 0
go add100(&cnt)
// 此处加到 100 了
fmt.Println(cnt)
go sub100(&cnt)
// 此处减到 0 了
wg.Wait()
fmt.Println(cnt)
}
----======== 互斥锁 解决 数据同步问题 ============-------------
package main
import (
"fmt"
"sync"
)
func add100(cnt *int) {
defer wg.Done()
for i := 0; i < 100000; i++ {
mutexLock.Lock()
*cnt += 1
mutexLock.Unlock()
}
}
func sub100(cnt *int){
defer wg.Done()
for i:= 0; i<100000; i++{
mutexLock.Lock()
*cnt -= 1
mutexLock.Unlock()
}
}
var wg = sync.WaitGroup{}
var mutexLock = sync.Mutex{}
func main(){
wg.Add(2)
var cnt = 0
go add100(&cnt)
// 此处加到 100 了
fmt.Println(cnt)
go sub100(&cnt)
// 此处减到 0 了
wg.Wait()
fmt.Println(cnt)
}
---===== 一般绝大多数 web 系统都是 读多写少 =====--------
// 读之间不产生影响, 写和读之间才会产生影响 ==》 读写锁
package main
import (
"fmt"
"sync"
"time"
)
var rwLock = sync.RWMutex{}
// 绝大部分 web 系统属于 读多写少类型
// 我们关注于 读 读 之间不产生影响, 只在 读写之间拥有 读写锁
var wg = sync.WaitGroup{}
func read(){
// 模拟读取数据
// 延迟注册一个 waitgroup 的 Done 方法
defer wg.Done()
// 此处我们加上 读写互斥锁 中的 读锁
rwLock.RLock()
fmt.Println("开始读取数据")
time.Sleep(time.Second) // 模拟 读取耗时 1 s
fmt.Println("完成读取数据")
// 释放 读锁
rwLock.RUnlock()
}
func write(){
// 模拟写操作
// 延迟注册一个 Done 方法
defer wg.Done()
// 添加写锁
rwLock.Lock()
// 模拟写操作耗时 10 s
fmt.Println("开始写入数据")
time.Sleep(time.Second * 10)
fmt.Println("完成写入数据")
// 释放写锁
rwLock.Unlock()
}
func main(){
var readCnt = 100
var writeCnt = 2
// 添加协程计数
wg.Add(readCnt + writeCnt)
// 模拟 100 次 读取操作
for i := 0; i<readCnt; i++{
go read()
}
// 模拟 2 次 写操作
for i := 0; i<writeCnt;i++{
go write()
}
// 等待所有协程完成
wg.Wait()
}
如果有来生,一个人去远行,看不同的风景,感受生命的活力。。。