36

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

 4 years ago
source link: https://www.tuicool.com/articles/Uva2eqQ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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("程序结束")
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK