Golang中go routines的使用示例与问题讨论
Golang中go routines的使用示例与问题讨论 https://play.golang.org/p/aCuUSqnRKIy
这段代码中哪部分(或哪些部分)是 Goroutine?
同时在学习 WaitGroup。
我从 Go Playground 的 GoDoc 中复制并粘贴了这段代码。
https://play.golang.org/p/E8qTrnwvoue
我哪里做错了?
func (*WaitGroup) Add
func (wg *WaitGroup) Add(delta int)
Add 方法将 delta 值累加。
请解释一下这个添加 delta 的概念。
更多关于Golang中go routines的使用示例与问题讨论的实战教程也可以访问 https://www.itying.com/category-94-b0.html
如果打扰到大家,我表示抱歉。我该如何将此标记为已解决?如果您愿意,我可以自行研究。
更多关于Golang中go routines的使用示例与问题讨论的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
cherilexvold1974: 这段代码的哪一部分是 Goroutine?
Goroutine 是由 go 关键字创建的并发工作单元。它会创建一个调用给定函数的“工作者”。
cherilexvold1974: 我哪里做错了?
和另一个帖子里的情况一样,你把代码粘贴到了某个地方…… 它需要放在 main 函数体内,或者放在一个由 main 调用的函数里,才能看到效果。
cherilexvold1974: 请解释一下这个增加 delta 的概念。
它只是将你作为 delta 传入的值加到内部计数器上。你无法直接访问那个计数器,只能向它添加任意值(wg.Add(delta))、将计数器减 1(wg.Done())或者等待它达到 0(wg.Wait())。
因此,假设你有一个“全新”的 WaitGroup,然后执行 wg.Add(6) 并启动 goroutine,接着执行 wg.Wait(),那么至少需要有 6 个 goroutine 在该 WaitGroup 上调用 wg.Done(),才能使“父级”继续执行。
cherilexvold1974:
Will you demonstrate?
我要演示什么?演示代码需要放在函数里才不会出现语法错误吗?你已经提供了足够多的例子了……
演示函数需要被调用才能生效?这道理很简单,不需要例子……但既然你要求了:
Alternative Go (Golang) Playground with syntax highlighting, turtle graphics and more
就这段代码而言,你不会看到任何输出,但一旦你取消第8行的注释,让它变成 foo() 而不是 // foo(),你就会看到输出。就这么简单……
cherilexvold1974:
What’s delta?
整段话就是为了解释它……归根结底,它只是一个任意的名字,由Go标准库的开发者选择,用来表示一个参数,该参数代表与其先前值的差值。这符合科学中“delta”的用法。但是,它本可以叫 diff、difference、n 或 x,甚至 fnoobrickl,尤其是后者没有任何解释性的上下文。
你不需要理解一个变量为什么叫这个名字,只需按照描述的方式使用它即可。
cherilexvold1974:
This whole thing is Greek to me.
抱歉,我无法解释得更简单了。
它的工作原理是这样的。WaitGroup维护着内部不可访问的状态,你可以向其中添加值,以1为步长递减,并等待其变为0。
这已经是最简单的解释了。我认为,去研究它的实现对你没有帮助。
NobbZ:
和另一个帖子里的情况一样,你把代码粘贴到了某个地方……它需要放在
main函数体内,或者放在一个会被main调用的函数里,才能看到效果。
你能演示一下吗?
NobbZ:
它只是把你作为
delta传入的任何值加到内部计数器上。
NobbZ:
delta
delta 是什么?
来自 Quora… 1 个回答
![]()
Brian MacKay,在 Inntec 工作
Delta 出现在数学和各种科学中,它总是指代 变化量。
当指代数据库时,delta 是一种学术性的描述方式,用来描述一个命令如何改变了数据。它可能指的是哪些行被删除了,或者单个行的旧值与新值的对比。
这不是大多数开发人员每天都需要考虑的事情,然而,每当我们使用数据库事务等功能时,我们都会从中受益。
事务允许我们对数据库进行一系列更改,但如果出现问题,可以将它们全部作为一个组取消。这可以防止我们的数据最终处于损坏或混乱的状态。
事务对我们来说很容易使用,但为了使该功能在数据库内部工作,一些非常聪明的人花费了他们职业生涯中相当多的时间来研究 delta。
这里有太多对我来说陌生的东西,我想我可能需要亲身体验才能理解。我打印了这个并做了书签,以便将来可以回来查看。
NobbZ:
它只是把你作为
delta传入的任何值加到内部计数器上。你无法直接访问那个计数器,只能向它添加任意值(wg.Add(delta)),将计数器减1(wg.Done())或者等待它达到0(wg.Wait())。所以假设你有一个“新”的 waitgroup,然后执行
wg.Add(6)并启动 goroutine,接着执行wg.Wait(),那么在
这整件事对我来说就像天书一样。
这段代码中,Goroutine 出现在以下部分:
- 第 20 行:
go func() { ... }()- 这是一个匿名函数作为 Goroutine 启动 - 第 26 行:
go worker(&wg)- 调用 worker 函数作为 Goroutine
关于 WaitGroup 的问题,第二个链接中的代码存在以下问题:
主要错误:
- Add 方法调用位置错误:在第 18 行
wg.Add(1)应该在启动 Goroutine 之前调用,而不是在 Goroutine 内部 - Wait 方法缺失:没有调用
wg.Wait()来等待所有 Goroutine 完成
修正后的代码示例:
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // Goroutine 完成时通知 WaitGroup
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1) // 在启动 Goroutine 前增加计数器
go worker(i, &wg)
}
wg.Wait() // 等待所有 Goroutine 完成
fmt.Println("All workers completed")
}
Add delta 概念解释:
Add(delta int) 方法用于增加或减少 WaitGroup 的计数器:
delta > 0:增加等待的 Goroutine 数量delta < 0:减少等待的 Goroutine 数量- 计数器不能为负数,否则会 panic
正确使用模式:
var wg sync.WaitGroup
// 启动前增加计数器
wg.Add(3) // 或 wg.Add(1) 在每个 Goroutine 启动前调用
go func() {
defer wg.Done()
// 任务逻辑
}()
go func() {
defer wg.Done()
// 任务逻辑
}()
go func() {
defer wg.Done()
// 任务逻辑
}()
wg.Wait() // 等待计数器归零
关键点:
Add()必须在 Goroutine 启动前调用- 每个 Goroutine 结束时必须调用
Done()(通常使用defer) Wait()会阻塞直到计数器归零- 不要重复使用 WaitGroup,完成一次等待后应创建新的实例

