• 10.Go-goroutine,waitgroup,互斥锁,channel和select


    10.1.goroutine

    goroutine的使用

    //Learn_Go/main.go
    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func demo(count int)  {
    	for i :=1; i < 10; i++{
    		fmt.Println(count,":",i)
    	}
    }
    
    func main() {
    	for i :=1; i < 10; i++{
    		go demo(i)
    	}
    	//添加休眠时间等待goroutine执行结束
    	time.Sleep(3e9)
    }
    

    10.2.waitgroup

    WaitGroup直译为等待组,其实就是计数器,只要计数器中有内容将一直阻塞

    WaitGroup有三种方法

    • Add(delta int)表示向内部计数器添加增量(delta),其中参数delta可以使负数
    • Done() 表示减少waitgroup计数器的值,应当在程序最后执行,相当于Add(-1)
    • Wait()  表示阻塞知道waitgroup计数器为0
    //Learn_Go/main.go
    package main
    
    import (
    	"fmt"
    	"sync"
    )
    
    func main() {
    	var wg sync.WaitGroup
    	wg.Add(5)
    	for i := 0; i < 5; i++{
    		go func(j int) {
    			fmt.Println("第",j,"次执行")
    			wg.Done()
    		}(i)
    	}
    	wg.Wait()
    	fmt.Println("程序结束")
    }

    10.3.互斥锁和读写锁

    (1)互斥锁

    可以使用sync.Mutex对内容加锁,互斥锁的使用场景

    • 多个gouroutine访问同一个函数代码段
    • 操作一个全局变量
    • 为了保证共享变量安全性,值安全性

     (2)读写锁

    Go语言中的map不是线程安全的,多个gouroutine同时操作会出现错误

    RWMutex可以添加多个读锁或者一个写锁,读写锁不能同时存在

    map在并发下读写就需要结合读写锁完成

    互斥锁表示锁的代码同一时间只能有一个goroutine运行,而读写锁表示在锁范围内数据的读写操作

    //Learn_Go/main.go
    package main
    
    import (
    	"fmt"
    	"sync"
    )
    
    func main() {
    	var rwm sync.RWMutex
    	var wg sync.WaitGroup
    	wg.Add(10)
    	m := make(map[int]int)
    	for i := 0; i < 10; i++{
    		go func(j int) {
    			rwm.Lock()
    			m[j] = j
    			fmt.Println(m)
    			rwm.Unlock()
    			wg.Done()
    		}(i)
    	}
    	wg.Wait()
    	fmt.Println("程序结束")
    }
    

    10.4.channel

    channel是进程内通信方式,每个channel只能传递一个类型的值,这个类型需要在声明channel时指定

    channel在Go中主要的两个作用:同步和通信

    (1)声明channel的语法

    • var 名称 chan 类型
    • var 名称 chan <- 类型       只写
    • var 名称 <- chan 类型       只读
    • 名称 := make(chan int)      无缓存chanel
    • 名称 := make(chan int)      无缓存channel
    • 名称 := make(chan int,100)     有缓存channel

     (2)操作channel的语法

    • ch <- 值          向ch中添加一个值
    • <- ch               从ch中取出一个值
    • a := <-ch         从ch中取出一个值并赋值给a
    • a,b := <-ch       从ch中取出一个值赋值给a,如果ch已经关闭或ch中没有值,b为false,

     (3)无论是向channel存数据还是取数据都会阻塞

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func main() {
    	ch := make(chan int)
    	go func() {
    		fmt.Println("执行")
    		ch <- 111     
    	}()
    	a := <- ch
    	fmt.Println(a)
    	fmt.Println("程序结束")
    }
    

     (4)使用channel实现gouroutine之间通信

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func main() {
    	ch1 := make(chan string)
    	ch2 := make(chan int)
    
    	go func() {
    		ch1 <- "derek"
    		ch2 <- 111
    	}()
    
    	go func() {
    		content := <- ch1
    		fmt.Println("取出数据:",content)       //取出数据: derek
    		ch2 <- 222
    	}()
    
    	a := <- ch2
    	b := <- ch2
    	fmt.Println(a,b)              //111 222
    	fmt.Println("程序结束")
    }
    

     (5)可以使用for range获取channel中内容

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func main() {
    	ch1 := make(chan int)
    	ch2 := make(chan int)
    
    	go func() {
    		for i := 0; i<10;i++{
    			ch1 <- i
    		}
    		ch2 <- 222
    	}()
    
    	go func() {
    		for n := range ch1{
    			fmt.Println(n)
    		}
    	}()
    	<- ch2
    	fmt.Println("程序结束")
    }
    

    10.5.select

    select执行过程

    • 每个case必须是一个IO操作
    • 哪个case可以执行就执行哪个
    • 所有case都不能执行时,执行default
    • 所有case都不能执行且没有default,将会阻塞
    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func main() {
    	ch1 := make(chan int,2)       //有缓存的channel
    	ch2 := make(chan int,3)
    	ch1 <- 111
    	ch2 <- 222
    	select {
    	case a := <-ch1:
    		fmt.Println(a)
    	case b := <-ch2:
    		fmt.Println(b)
    	default:
    		fmt.Println("错误")
    	}
    }
    

     select多和for循环结合使用

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func main() {
    	ch := make(chan int)
    	for i := 0; i < 10;i++{
    		go func(j int) {
    			ch <- j
    		}(i)
    	}
    	//用for循环一直接受
    	for {
    		select {
    		case a := <- ch:
    			fmt.Println(a)
    		default:
    		}
    	}
    }
     
     
     
  • 相关阅读:
    C#基于引用创建单链表
    锻炼自己的思维模式
    [数据结构]C#基于数组实现泛型顺序表
    DEV Express
    [LeetCode] Combinations (bfs bad、dfs 递归 accept)
    [LeetCode] Wildcard Matching
    [LeetCode] Remove Duplicates from Sorted List II
    [LeetCode] Partition List
    [LeetCode] Scramble String(树的问题最易用递归)
    [LeetCode] Decode Ways(DP)
  • 原文地址:https://www.cnblogs.com/gaidy/p/11887150.html
Copyright © 2020-2023  润新知