小伙伴关心的问题:golang并发 select default(golang并发),本文通过数据整理汇集了golang并发 select default(golang并发)相关信息,下面一起看看。

golang并发 select default(golang并发)

并发

goroutine和wg

func main() { // 来实现并发任务的同步执行 // wg 防止main的goroutine执行完了之后,自己定义的goroutine还没有执行完 var wg sync.WaitGroup for i:=0; i<5; i++{ go func(index int) { defer wg.Done() // defer会在最后执行 wg.Done 计数器减1 fmt.Println(index) }(i) wg.Add(1) // 计数器加1 这个数字是可以随便定义的,但是在Done里自己处理 } wg.Wait() // 阻塞,直到计数器变为0 fmt.Println("meila") }

channel

管道基本操作ch := make(chan int 10) //定义一个i能存储10个int类型的管道 ch <- 1 // 把1发送到管道中 a := <- ch // 从管道ch中拿值 close(ch) // 关闭管道 for range可以从管道中取值,通道关闭后会退出for range通道被关闭后,再从通道中取值会一直收到零值无缓冲通道必须有一个接收者,也被叫做阻塞的通道无缓冲和有缓冲的区别就是有没有在设置容量package main import ( "fmt" ) func f3(ch chan int) { for v := range ch { fmt.Println(v) } } // for range来接受通道中的值,就不用和f1自己来判断了 func f1(ch1 chan int) { for i := 0; i < 100; i++ { ch1 <- i } close(ch1) } func f2(ch1, ch2 chan int) { for { i, ok := <-ch1 // 多返回值模式,没有值了之后ok会是false if !ok { break } ch2 <- i * i } close(ch2) } func main() { ch1 := make(chan int) ch2 := make(chan int) go f1(ch1) go f2(ch1, ch2) /* 执行f1和f2要加上goroutine,因为ch1和ch2都是无缓冲的通道,无缓冲的通道必须有一个接收方才能发送成功 不加goroutine的话,就会造成一直在等待接收者,造成死锁 无缓冲就是类似快递员送快递,必须有人签收 有缓冲就是类似快递放到快递柜里,容量就是这个快递柜最多能放多少快递 */ for i := range ch2 { // for range可以用来判断通道关闭 fmt.Println(i) } for i := 0; i < 5; i++ { go func() { fmt.Println(i) }() } } 单向通道可以限制管道在函数中只能发送或只能接收// <- chan int 只接受通道 x := <- ch 从通道中接受值 // chan <- 只发送通道 ch <- 10 把10发送到通道中 select 多路复用可处理一个或多个 channel 的发送/接收操作。如果多个 case 同时满足,select 会随机选择一个执行。对于没有 case 的 select 会一直阻塞,可用于阻塞 main 函数,防止退出。实际开发中可能存在不知道什么时候退出的情况,就可以使用selectpackage main import "fmt" func main() { ch := make(chan int, 1) for i := 1; i <= 10; i++ { select { case x := <-ch: fmt.Println(x) case ch <- i: } } } /* 输出 1 3 5 7 9 */

并发和锁

为了防止多个goroutine操作同一个资源,需要在操作的时候加上锁锁有互斥锁和读写互斥锁package main import ( "fmt" "sync" "time" ) var ( x int64 wg sync.WaitGroup mutex sync.Mutex // 互斥锁,同一时间只有一个人能用 rwMutex sync.RWMutex // 读写互斥锁,用于读多写少的场景 /* 读写锁分为两种:读锁和写锁。 当一个 goroutine 获取到读锁之后,其他的 goroutine 如果是获取读锁会继续获得锁,如果是获取写锁就会等待; 当一个 goroutine 获取写锁之后,其他的 goroutine 无论是获取读锁还是写锁都会等待 */ ) func writeWithLock() { mutex.Lock() // 加锁 x = x + 1 time.Sleep(10 * time.Millisecond) mutex.Unlock() // 解锁 wg.Done() } func readWithLock() { mutex.Lock() time.Sleep(time.Millisecond) mutex.Unlock() wg.Done() } func writeWithRWLock() { rwMutex.Lock() // 加写锁 x = x + 1 time.Sleep(10 * time.Millisecond) rwMutex.Unlock() //解开写锁 wg.Done() } func readWithRWLock() { rwMutex.RLock() // 加读锁 time.Sleep(time.Millisecond) rwMutex.RUnlock() // 解开读锁 wg.Done() } func do(wf, rf func(), wc, rc int) { start := time.Now() // wc个并发写操作 for i := 0; i < wc; i++ { wg.Add(1) go wf() } // rc个并发读操作 for i := 0; i < rc; i++ { wg.Add(1) go rf() } wg.Wait() cost := time.Since(start) fmt.Printf("x:%v cost:%v\n", x, cost) } func main() { do(writeWithLock, readWithLock, 10, 1000) do(writeWithRWLock, readWithRWLock, 10, 1000) // x:10 cost:117.207592ms }

sync方法

sync.WaitGroup 用来实现并发任务的同步Add(x) 计数器加xDone() 计数器减1Wait() 阻塞,直到计数器变为0sync.Once 确保某些操作只会执行一次,比如加载配置文件之类的package main import ( "image" "sync" ) var icons map[string]image.Image var loadIconsOnce sync.Once func loadIcons() { icons = map[string]image.Image{ /* 不用Sync.Once的话,在并发操作时,可能刚初始化完map就会被调用,倒是值一直时nil */ "left": loadIcon("left.png"), "up": loadIcon("up.png"), "right": loadIcon("right.png"), "down": loadIcon("down.png"), } } // Icon 是并发安全的 func Icon(name string) image.Image { loadIconsOnce.Do(loadIcons) /* sync.Once只有一个Do方法 确保了loadIcon只会被执行一次 */ return icons[name] } sysc.map 并发的时候使用的mappackage main import ( "fmt" "strconv" "sync" ) // 并发安全的map var m = sync.Map{} func main() { wg := sync.WaitGroup{} // 对m执行20个并发的读写操作 for i := 0; i < 20; i++ { wg.Add(1) go func(n int) { key := strconv.Itoa(n) m.Store(key, n) // 存储key-value value, _ := m.Load(key) // 根据key取值 fmt.Printf("k=:%v,v:=%v\n", key, value) wg.Done() }(i) } wg.Wait() }

更多golang并发 select default(golang并发)相关信息请关注本站,本文仅仅做为展示!