专栏首页有趣的django10.Go-goroutine,waitgroup,互斥锁,channel和select

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:
		}
	}
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Golang 常用并发编程技巧

    Golang 是最早将 CSP 原则纳入其核心的语言之一,并将这种并发编程风格引入到大众中。CSP 指的是 Communicating Sequential P...

    CS实验室
  • Golang 并发编程之同步原语

    当提到并发编程、多线程编程时,我们往往都离不开『锁』这一概念,Go 语言作为一个原生支持用户态进程 Goroutine 的语言,也一定会为开发者提供这一功能,锁...

    KevinYan
  • 可能不知道的关于golang 的10件事情

    匿名结构体 最常见的匿名用法,不用单独定义一个结构体类型 var config struct { APIKey s...

    李海彬
  • Go语言 | 并发设计中的同步锁与waitgroup用法

    今天是golang专题的第16篇文章,我们一起来聊聊golang当中的并发相关的一些使用。

    TechFlow-承志
  • 6.824 2020 视频笔记五:Go Concurrency

    MIT 今年终于主动在 Youtube 上放出了随堂视频资料,之前跟过一半这门课,今年打算刷一下视频,写写随堂笔记。该课程以分布式基础理论:容错、备份、一致性为...

    青藤木鸟
  • Golang并发编程控制

    重学编程之Golang的plan中的上一篇文章我向大家介绍了,并发编程基础,goroutine的创建,channel,正由于go语言的简洁性,我们可以简易快速的...

    PayneWu
  • go 并发编程

    Go 语言在 sync 包中提供了用于同步的一些基本原语,包括常见的 sync.Mutex、sync.RWMutex、sync.WaitGroup、sync.O...

    haifeiWu
  • golang面试

    Michel_Rolle
  • Go中的同步与锁

    最近学习了Go语言中同步包中的互斥锁、读写锁、Once、waitGroup。在并发程序开发的过程中,这两种锁是非常重要的,包括对共享资源进行访问控制的时候。sy...

    李海彬
  • GoLang并发控制(上)

    首先解释golang中的channel:channel是go中的核心部分之一,结构体简单概括就是一个ring队列+一个锁 有兴趣的同学可以去研究一下源码构建。在...

    李海彬
  • Go语言基于共享变量的并发

    一个特定类型的方法和操作函数是并发安全的,那么所有它的访问方法和操作都是并发安全的。导出包级别的函数一般情况下都是并发安全的,package级的变量没法被限制在...

    李海彬
  • Go语言基于共享变量的并发

    一个特定类型的方法和操作函数是并发安全的,那么所有它的访问方法和操作都是并发安全的。导出包级别的函数一般情况下都是并发安全的,package级的变量没法被限制在...

    李海彬
  • Go语言基于共享变量的并发

    一个特定类型的方法和操作函数是并发安全的,那么所有它的访问方法和操作都是并发安全的。导出包级别的函数一般情况下都是并发安全的,package级的变量没法被限制在...

    李海彬
  • Go语言sync包的应用详解

    在并发编程中同步原语也就是我们通常说的锁的主要作用是保证多个线程或者 goroutine在访问同一片内存时不会出现混乱的问题。Go语言的sync包提供了常见的并...

    KevinYan
  • 6.824 2020 视频笔记二:RPC和线程

    MIT 今年终于主动在 Youtube 上放出了随堂视频资料,之前跟过一半这门课,今年打算刷一下视频,写写随堂笔记。该课程以分布式基础理论:容错、备份、一致性为...

    青藤木鸟
  • GO语言高并发学习心得体会例

    信号 sigRecv1:=make(chan os.Signal,1)sigs1:=[]os.Signal{syscall.SIGINT,syscall.SIG...

    李海彬
  • GO语言高并发学习心得体会例

    <div class="blockcode"><blockquote>信号 sigRecv1:=make(chan os.Signal,1) sigs1...

    李海彬
  • 即时通讯软件可以用GO语言实现吗

    四个方面特点: 1. 并发支持 对于及时通讯、网络编程等方面,并发支持一定是并不可少的。 goroutine,用户态"线程",大家所说的协程,支持并发操作。已经...

    李海彬
  • Gopher 2019 Go并发编程的分享

    昨天参加了 Gopher China 2019 大会,分享了《Go并发编程实践》的主题,在这一篇博客中总结一下。

    李海彬

扫码关注云+社区

领取腾讯云代金券