golang学习(2)

go modules

同目录下,不同的go文件不能有不同的package,只能有一个main
包的引用
在这里插入图片描述在这里插入图片描述使用WaitGroup控制协程控制
在这里插入图片描述在这里插入图片描述
互斥锁,使用sync.Mutex 的lock和unlock来实现互斥操作

package main

import (
	"fmt"
	"sync"
)

var total int
var wg sync.WaitGroup
var lock sync.Mutex
// 互斥锁
func add()  {
	defer wg.Done()
	for i :=0; i<1000000; i++ {
		lock.Lock()
		total += 1
		lock.Unlock()
	}
}

func sub()  {
	defer wg.Done()
	for i := 0; i<1000000; i++{
		lock.Lock()
		total -= 1
		lock.Unlock()
	}
}
func main()  {
	wg.Add(2) // 两个协程
	go add()
	go sub()
	wg.Wait()
	fmt.Println(total)
}

同步问题,使用sync.RWMutex的 来实现读写锁

package main

import (
	"fmt"
	"sync"
	"time"
)

var total int
var wg sync.WaitGroup
var lock sync.Mutex
var rwLock sync.RWMutex
// 互斥锁
func add()  {
	defer wg.Done()
	for i :=0; i<1000000; i++ {
		lock.Lock()
		total += 1
		lock.Unlock()
	}
}

func sub()  {
	defer wg.Done()
	for i := 0; i<1000000; i++{
		lock.Lock()
		total -= 1
		lock.Unlock()
	}
}
func read()  {
	defer wg.Done()
	rwLock.RLock()
	fmt.Println("开始读数据")
	time.Sleep(time.Second)
	fmt.Println("读取成功")
	rwLock.RUnlock()
}
func write()  {
	defer wg.Done()
	rwLock.Lock()
	fmt.Println("开始修改数据")
	time.Sleep(time.Second*10)
	fmt.Println("修改成功")
	rwLock.Unlock()
}

func main()  {
	wg.Add(5) // 两个协程
	for i:=0; i<5;i++ {
		go read()
	}
	wg.Wait()
	fmt.Println(total)
}

channel机制
在这里插入图片描述

使用range遍历channel

func consumer(queue chan int)  {
	defer wg.Done()
	for{
		data, ok := <- queue
		if !ok{
			break
		}
		fmt.Println(data)
		time.Sleep(time.Second)

	}
}
func main()  {

	var msg chan int

	msg = make(chan int, 1)

	msg <- 1
	wg.Add(1)
	go consumer(msg)
	msg <- 2

	close(msg)
	wg.Wait()
}

使用 chan<-和chan<- 设置为单向的管道
使用channel容易出现deallock是因为:msg <- 1是放数据进去,放进去需要获取锁,但是没有取数据,故会出现死锁
在这里插入图片描述
故:
在这里插入图片描述
select
在这里插入图片描述

	timeout := make(chan bool, 2)
	go func() {
		//该goroutine 如果执行时间超过了5s,那么就报告给主的goroutine
		time.Sleep(time.Second*5)
		timeout <- true
	}()

	timeout2 := make(chan bool, 2)
	go func() {
		//该goroutine 如果执行时间超过了5s,那么就报告给主的goroutine
		time.Sleep(time.Second*1)
		timeout2 <- true
	}()
	select {
	case <-timeout:
		fmt.Println("超时了")
	case <-timeout2:
		fmt.Println("超时了")
	default:
		fmt.Println("继续下一次")

	}

需求:取消一个定时监控cpu信息的协程
可以由三种方法来完成:①,全局变量,②:使用select 的 case 和default来完成。③:使用context机制,代码如下:

// context
func cpuInfo(ctx context.Context)  {
	defer wg.Done()
	for  {
		select {
		case <- ctx.Done():
			fmt.Println("监控退出")
			return
		default:
			time.Sleep(time.Second)
			fmt.Println("获取cpu信息成功")

		}
	}
}
func main()  {
	wg.Add(1)
	ctx, cancel := context.WithCancel(context.Background())
	go cpuInfo(ctx)
	time.Sleep(time.Second * 6)
	cancel()
	wg.Wait()
	fmt.Println("信息监控完成")
}

context的特性:父context结束,子context也结束,多个context一并结束
golang提供的context有三种:context.WithDeadline() context.WithTimeout() context.WithValue()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值