区块链中文技术社区 - Golang基础学习
type: channel
link: https://bcskill.com/index.php/tag/Golang基础学习/
items: Go sync.WaitGroup的用法
items: go语言中使用new和make创建map时的差异

Go sync.WaitGroup的用法
type: item
date: 2022-02-16T17:57:18+08:00
description: 介绍 经常会看到以下了代码： package main import ( "fmt" "time" ) func main(){ for i := 0; i < 100 ; i++{ go fmt.Println(i) } time.Sleep(time.Second) } 主线程为了等待goroutine都运行完毕，不得不在程序的末尾使用time.Sleep() 来睡眠一段时间，等待其他线程充分运行。对于简单的代码，100个for循环可以在1秒之内运行完毕，time.Sleep() 也可以达到想要的效果。 但是对于实际生活的大多数场景来说，1秒是不够的，并且大部分时候我们都无法预知for循环内代码运行时间的长短。这时候就不能使用time.Sleep() 来完成等待操作了。 可以考虑使用管道来完成上述操作： func main() { c := make(chan bool, 100) for i := 0; i < 100; i++ { go func(i int) { fmt.Println(i) c <- true }(i) } for i := 0; i < 100; i++ { <-c } } 首先可以肯定的是使用管道是能达到我们的目的的，而且不但能达到目的，还能十分完美的达到目的。 但是管道在这里显得有些大材小用，因为它被设计出来不仅仅只是在这里用作简单的同步处理，在这里使用管道实际上是不合适的。而且假设我们有一万、十万甚至更多的for循环，也要申请同样数量大小的管道出来，对内存也是不小的开销。 对于这种情况，go语言中有一个其他的工具sync.WaitGroup 能更加方便的帮助我们达到这个目的。 WaitGroup 对象内部有一个计数器，最初从0开始，它有三个方法：Add(), Done(), Wait() 用来控制计数器的数量。Add(n) 把计数器设置为n ，Done() 每次把计数器-1 ，wait() 会阻塞代码的运行，直到计数器地值减为0。 使用WaitGroup 将上述代码可以修改为： func main() { wg := sync.WaitGroup{} wg.Add(100) for i := 0; i < 100; i++ { go func(i int) { fmt.Println(i) wg.Done() }(i) } wg.Wait() } 这里首先把wg 计数设置为100， 每个for循环运行完毕都把计数器减一，主函数中使用Wait() 一直阻塞，直到wg为零——也就是所有的100个for循环都运行完毕。相对于使用管道来说，WaitGroup 轻巧了许多。 注意事项 1. 计数器不能为负值 我们不能使用Add() 给wg 设置一个负值，否则代码将会报错： panic: sync: negative WaitGroup counter goroutine 1 [running]: sync.(*WaitGroup).Add(0xc042008230, 0xffffffffffffff9c) D:/Go/src/sync/waitgroup.go:75 +0x1d0 main.main() D:/code/go/src/test-src/2-Package/sync/waitgroup/main.go:10 +0x54 同样使用Done() 也要特别注意不要把计数器设置成负数了。 2. WaitGroup对象不是一个引用类型 WaitGroup对象不是一个引用类型，在通过函数传值的时候需要使用地址： func main() { wg := sync.WaitGroup{} wg.Add(100) for i := 0; i < 100; i++ { go f(i, &wg) } wg.Wait() } // 一定要通过指针传值，不然进程会进入死锁状态 func f(i int, wg *sync.WaitGroup) { fmt.Println(i) wg.Done() } 转载自：https://blog.csdn.net/u013474436/article/details/88749749

go语言中使用new和make创建map时的差异
type: item
date: 2022-02-16T17:28:41+08:00
description: 在go语言中，可以使用new和make来创建map类型的变量，但是它们之间有很明显的不同，使用new来创建map时，返回的内容是一个指针，这个指针指向了一个所有字段全为0的值map对象，需要初始化后才能使用，而使用make来创建map时，返回的内容是一个引用，可以直接使用。他们之间的差异大概如下图所示： 下面来看它们的具体用法 使用new来创建并使用map： //使用new创建一个map指针 ma := new(map[string]int) //第一种初始化方法 *ma = map[string]int{} (*ma)["a"] = 44 fmt.Println(*ma) //第二种初始化方法 *ma = make(map[string]int, 0) (*ma)["b"] = 55 fmt.Println(*ma) //第三种初始化方法 mb := make(map[string]int, 0) mb["c"] = 66 *ma = mb (*ma)["d"] = 77 fmt.Println(*ma) 使用make来创建并使用map: ma := make(map[string]int) ma["a"] = 33 fmt.Println(ma) 转载自：https://blog.csdn.net/choumin/article/details/89893830