1 回答
TA贡献1770条经验 获得超3个赞
您应该完成围棋之旅,并特别关注围棋例程以及查看等待组。我将在这里简要介绍适用的概念。
关键字go
在Go中,同时运行函数非常容易。鉴于以下代码,我只需要在 前面添加前缀,使其与程序的其余部分同时运行。go
blockingCode
func blockingCode() {
time.Sleep(time.Second)
fmt.Println("finishing blocking")
}
func main() {
fmt.Println("starting main")
go blockingCode()
fmt.Println("finishing main")
}
你会注意到关于这一点的几件事:
如果我删除了前缀,该函数将被阻止,您将看到所有三个打印语句,最后两个比第一个打印语句晚一秒(去游乐场)。
go
如果我重新添加前缀,该函数不会阻塞,但您不会看到 print 语句。这是因为主函数(主 go 例程)在完成之前终止。这就是等待组发挥作用的地方。
go
fmt.Println("finishing blocking")
blockingCode
WaitGroup
要等待多个戈鲁丁完成,我们可以使用一个等待组。https://gobyexample.com/waitgroups。
将等待组视为原子计数器,其中调用阻塞直到计数器为 0。生成 go 例程时,会递增计数器 (),在完成 go 例程时,会取消递增计数器 ()。下面是支持等待组的代码。去游乐场wg.Wait
wg.Add
wg.Done
func blockingCode(wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(time.Second)
fmt.Println("finishing blocking")
}
func main() {
wg := sync.WaitGroup{}
fmt.Println("starting main")
wg.Add(1)
go blockingCode(&wg)
wg.Wait()
fmt.Println("finishing main")
}
现在,这会产生与我们上面看到的完全相同的行为 - 该函数将阻塞,您将看到所有三个print语句,最后两个比第一个延迟一秒钟打印 - 那么为什么我们首先将其并发?不同之处在于,我们现在可以同时运行许多事情,而不是按顺序运行很多事情。在这种情况下,我们没有看到并发的好处的原因是因为我们只同时做一件事。
让我们调整示例以运行多次。您会注意到,脚本运行所需的时间几乎相同,即使我们调用的 blockCode 需要整整一秒钟才能运行,三次,如果我们删除关键字和等待组,我们会看到此代码至少需要三秒钟才能运行 go Playground。blockingCodego
func blockingCode(wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(time.Second)
fmt.Println("finishing blocking")
}
func main() {
wg := sync.WaitGroup{}
fmt.Println("starting main")
wg.Add(1)
go blockingCode(&wg)
wg.Add(1)
go blockingCode(&wg)
wg.Add(1)
go blockingCode(&wg)
wg.Wait()
fmt.Println("finishing main")
}
您的示例
您选择如何处理并发行为很大程度上取决于应用程序的细节,但是像这样的东西应该实现我在这里提供的并发概念,并允许您与加载程序同时运行监视器。
func main() {
// ...
wg := sync.WaitGroup{}
for a := 0; a < len(j)/2; a++ {
cpucore := j[a]
wg.Add(1)
go runCpuLoader(&wg, sampleInterval, cpuload, duration, cpucore)
}
wg.Wait()
}
func runCpuLoader(wg *sync.WaitGroup, sampleInterval time.Duration, cpuload float64, duration float64, cpu int) {
defer wg.Done()
// ...
}
- 1 回答
- 0 关注
- 82 浏览
添加回答
举报