vscode-go goroutine/chan/sync.waitgroup/sync.mutex/sync.rwmutex/panic/recover

1. go test -v 新增配置默认支持log/print

    "go.testFlags": ["-v"],

2. 新建文件增加代码头文件

    "fileheader.customMade":{
        "Description": "", 
        "Author": "xxxxx", 
        "Date": "Do not edit",
        "LastEditTime": "Do not edit",
        "LastEditors": "by edit",
    },

3. WaitGroup - “等待”组

var 实例名 sync.WaitGroup 

实例化完成后,就可以使用它的几个方法:

  • Add:初始值为0,你传入的值会往计数器上加,这里直接传入你子协程的数量

  • Done:当某个子协程完成后,可调用此方法,会从计数器上减一,通常可以使用 defer 来调用。

  • Wait:阻塞当前协程,直到实例里的计数器归零。

package basego

import (
	"fmt"
	"sync"
)

func worker(x int, wg *sync.WaitGroup) {
	defer wg.Done()
	for i := 0; i < 5; i++ {
		fmt.Printf("worker %d: %d\n", x, i)
	}
}

func SyncMain() {
	var wg sync.WaitGroup

	wg.Add(2)
	go worker(1, &wg)
	go worker(2, &wg)

	wg.Wait()
}

4. goroutine使用说明

一个 Go 程序的入口通常是 main 函数,程序启动后,main 函数最先运行,我们称之为 main goroutine

在 main 中或者其下调用的代码中才可以使用 go + func() 的方法来启动协程。

5. channel 信道

goroutine 是 Go语言程序的并发执行的基本单元,多个 goroutine 的通信是需要依赖本文的主人公 —— channel 。channel,中文翻译有叫通道,也有叫信道的。以下为了方便,我统一称之为 信道 。

信道,就是一个管道,连接多个goroutine程序 ,它是一种队列式的数据结构,遵循先入先出的规则。

按照是否可缓冲数据可分为:缓冲信道 与 无缓冲信道

缓冲信道

允许信道里存储一个或多个数据,这意味着,设置了缓冲区后,发送端和接收端可以处于异步的状态。

pipline := make(chan int, 10)

无缓冲信道

在信道里无法存储数据,这意味着,接收端必须先于发送端准备好,以确保你发送完数据后,有人立马接收数据,否则发送端就会造成阻塞,原因很简单,信道中无法存储数据。也就是说发送端和接收端是同步运行的。

pipline := make(chan int)

// 或者
pipline := make(chan int, 0)

6.  Mutex & RWMutex

这个包有两个很重要的锁类型

一个叫 Mutex, 利用它可以实现互斥锁。
一个叫 RWMutex,利用它可以实现读写锁。

Mutex,互斥锁(全称 mutual exclusion)是为了来保护一个资源不会因为并发操作而引起冲突导致数据不准确。

lock := &sync.Mutex{}

 

RWMutex,读写锁,它将程序对资源的访问分为读操作和写操作

lock := &sync.RWMutex{}
  • 为了保证数据的安全,它规定了当有人还在读取数据(即读锁占用)时,不允计有人更新这个数据(即写锁会阻塞)

  • 为了保证程序的效率,多个人(线程)读取数据(拥有读锁)时,互不影响不会造成阻塞,它不会像 Mutex 那样只允许有一个人(线程)读取同一个数据。

 7. panic & recover

Golang 异常的抛出与捕获,依赖两个内置函数:

  • panic:抛出异常,使程序崩溃

  • recover:捕获异常,恢复程序或做收尾工作

revocer 调用后,抛出的 panic 将会在此处终结,不会再外抛,但是 recover,并不能任意使用,必须得在 defer 下才能发挥用途

panic 会导致整个程序退出,但在退出前,若有 defer 延迟函数,还是得执行完 defer 。但 defer 在多个协程之间是没有效果的,在子协程里触发 panic,只能触发自己协程内的 defer,而不能调用 main 协程里的 defer 。

8. go module

  • go mod init:初始化go mod, 生成go.mod文件,后可接参数指定 module 名,上面已经演示过。

  • go mod download:手动触发下载依赖包到本地cache(默认为$GOPATH/pkg/mod目录)

  • go mod graph:打印项目的模块依赖结构

  • go mod tidy  :添加缺少的包,且删除无用的包

  • go mod verify  :校验模块是否被篡改过

  • go mod why:查看为什么需要依赖

  • go mod vendor  :导出项目所有依赖到vendor下

  • go mod edit  :编辑go.mod文件,接 -fmt 参数格式化 go.mod 文件,接 -require=golang.org/x/text 添加依赖,接 -droprequire=golang.org/x/text 删除依赖,详情可参考 go help mod edit

  • go list -m -json all:以 json 的方式打印依赖详情

如何给项目添加依赖(写进 go.mod)呢?

有两种方法:

  • 你只要在项目中有 import,然后 go build 就会 go module 就会自动下载并添加。

  • 自己手工使用 go get 下载安装后,会自动写入 go.mod 。

如果使用 go modules

你导入的包如果有域名,都会先在 $GOPATH/pkg/mod 下查找,找不到就连网去该网站上寻找,找不到或者找到的不是一个包,则报错。

而如果你导入的包没有域名(比如 "fmt"这种),就只会到 $GOROOT 里查找。

还有一点很重要,当你的项目下有 vendor 目录时,不管你的包有没有域名,都只会在 vendor 目录中想找。

9.  类型断言

Type Assertion(中文名叫:类型断言)

  • 检查 i 是否为 nil
  • 检查 i 存储的值是否为某个类型
t, ok:= i.(T)
//  Type Switch

func findType(i interface{}) {
    switch x := i.(type) {
    case int:
        fmt.Println(x, "is int")
    case string:
        fmt.Println(x, "is string")
    case nil:
        fmt.Println(x, "is nil")
    default:
        fmt.Println(x, "not type matched")
    }
}

 

10. select-case

  • select 只能用于 channel 的操作(写入/读出),而 switch 则更通用一些;

  • select 的 case 是随机的,而 switch 里的 case 是顺序执行;

  • select 要注意避免出现死锁,同时也可以自行实现超时机制;

  • select 里没有类似 switch 里的 fallthrough 的用法;

  • select 不能像 switch 一样接函数或其他表达式。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值