Go语言并发编程

Go语言并发编程

一、线程等待

type WaitGroup结构体(Add、Done、Wait):

package main

import (
	"fmt"
	"sync"
)

func mainWait() {
	for i := 1; i < 10; i++ {
		fmt.Println("main:", i)
	}
}
func TestWait(wg *sync.WaitGroup) {
	defer wg.Done() //减少信号次数
	for i := 1; i < 100; i++ {
		fmt.Println("Route:", i)
	}
}
func main() {
	var wg sync.WaitGroup //设置信号量
	wg.Add(1)             //加上信号次数(次数用完Wait方法阻塞等待的所有线程都会释放)
	go TestWait(&wg)//这里一定要传指针,不然无法修改wg的值,线程一直等待会死锁
	mainWait()
	wg.Wait() //等待信号结束
}

注:Wait和Add要在例程外面,Done在例程里面,不然容易直接结束线程等待

二、互斥锁

背景:多个例程对同一数据进行操作,需要加锁,类似Redis线程锁

type Mutex结构体(Lock,Unlock)

package main

import (
	"fmt"
	"sync"
)

func main() {
	var a int = 2000
	var b int = 2000
	var wg sync.WaitGroup
	var locker sync.Mutex   //定义锁变量
	wg.Add(2)
	go func() {
		locker.Lock()   //加锁
		a = a + 1000
		b = b - 1000
		wg.Done()
		locker.Unlock()   //解锁,可以使用defer,但是需要匿名函数
	}()
	go func() {
		locker.Lock()
		a = a - 1000
		b = b + 1000
		wg.Done()
		locker.Unlock()
	}()
	wg.Wait()
	fmt.Printf("总共为:%d", a+b)
}

三、sync/atomic原子性操作

1、底层加锁原理;

2、具体怎么使用查看官方文档;

3、看为一个整体操作

四、管道

具体知识前往Go语言基础管道,下面只讲解部分知识点

1、无缓冲区管道读写

写和读的操作必须成对,不然会进行阻塞

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan struct{})
	go func() {
		time.Sleep(5 * time.Second) //设置等待,5s后才能写入
		ch <- struct{}{}            //空结构体可以节约内存
	}()
	<-ch //主线程阻塞,一直等待线程写入后读取
	fmt.Println("end")
}

2、关闭管道

管道关闭后无法继续写入

	close(ch)                   //关闭管道
	ch <- 1
Panic错误(可以恢复的错误):
    panic: send on closed channel

3、阻塞发生情况
在这里插入图片描述
阻塞和死锁不同,死锁是没人写,阻塞是读写不同步

4、监听管道

package main

import (
	"fmt"
	"time"
)

func main() {
	var ch1 chan struct{} = make(chan struct{})
	var ch2 chan struct{} = make(chan struct{})
	go func() {
		time.Sleep(4 * time.Second)
		ch1 <- struct{}{}
	}()
	go func() {
		time.Sleep(3 * time.Second)
		ch2 <- struct{}{}
	}()
	select {
	case <-ch1:
		fmt.Println("This is ch1")
	case <-ch2:
		fmt.Println("This is ch2")
	}
}

实例,main函数超过5秒就输出超时,没5秒就输出
在这里插入图片描述
第二种方法:

package main

import (
	"fmt"
	_ "fmt"
	"time"
)

func main() {
	res := make(chan time.Time)
	go func() {
		time.Sleep(6 * time.Second)
		res <- time.Now()
	}()
	select {
	case <-res:
		fmt.Println("任务成功")
	case <-time.After(5 * time.Second):
		fmt.Println("已经超时")
	}
}

五、读写锁

作用;并发的修改同一文件数据(读取数据不用),因为互斥锁会把所有操作都锁起来,包括读的操作,会导致效率下降,所以出现了读写锁。

	//读写锁
	//获取锁 Lock Rlock
	//释放锁 Unlock Runlock
	//写写互斥,写读互斥,读读不互斥(Rlock,Rlock)
package main

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

func main() {
	var wg sync.WaitGroup
	var locker sync.RWMutex
	wg.Add(2)
	go func() {
		fmt.Println("A before")
		locker.RLock()
		fmt.Println("A Do")
		time.Sleep(10 * time.Second)
		locker.RUnlock()
		fmt.Println("A After")
		wg.Done()
	}()
	go func() {
		time.Sleep(time.Second * 1)
		fmt.Println("B before")
		locker.RLock()
		fmt.Println("B Do")
		locker.RUnlock()
		fmt.Println("B After")
		wg.Done()
	}()
	wg.Wait()
}

六、Cond锁

//type Cond 对象的使用()
package main

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

func main() {
	var locker sync.Mutex
	var wg sync.WaitGroup
	wg.Add(2)
	cond := sync.NewCond(&locker) //创建cond结构体指针
	go func() {
		cond.L.Lock()
		cond.Wait()   //起到了阻塞作用
		fmt.Println("我得到信号了")
		wg.Done()
		cond.L.Unlock()

	}()
	go func() {
		time.Sleep(time.Second * 5)
		wg.Done()
		cond.Broadcast()
	}()
	wg.Wait()
}

七、Once

在这里插入图片描述
八、Pool对象

没有就直接创建池对象,有就直接用

package main

import (
	"fmt"
	_ "fmt"
	"sync"
)

type student struct {
	id int
}

func main() {
	index := 0
	pool := sync.Pool{
		New: func() interface{} {
			index++
			stu := student{
				id: index,
			}
			return &stu
		},
	}
	c := pool.Get()
	fmt.Println(c) //pool中创建c
	c1 := pool.Get()
	fmt.Println(c1)  //pool中创建c1
	pool.Put(c1)     //把c1放回去
	c2 := pool.Get() //再拿的时候pool中有c1,所以直接取c1
	fmt.Println(c2)
}

九、Runtime

Gosched调度获取

package main

import (
	"fmt"
	_ "fmt"
	"runtime"
	"sync"
)

func main() {
	runtime.Gosched() // 让出CPU时间 time.Sleep()

	// var wg *sync.WaitGroup
	wg := new(sync.WaitGroup)

	for i := 0; i < 2; i++ {
		wg.Add(1)
		go func(i int) {
			for ch := 'A'; ch < 'Z'; ch++ {
				fmt.Printf("%d: %c\n", i, ch)
				runtime.Gosched()
			}
			wg.Done()
		}(i)
	}

	wg.Wait()
}

如果看完对自己有所帮助,请点赞支持。谢谢大家

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值