Golang中sync.Once的使用示例分享 - https://play.golang.org/p/GRnbfUG4nut

Golang中sync.Once的使用示例分享 - https://play.golang.org/p/GRnbfUG4nut https://play.golang.org/p/GRnbfUG4nut

这里有什么问题?

10 回复

main 函数执行大括号内的代码!

更多关于Golang中sync.Once的使用示例分享 - https://play.golang.org/p/GRnbfUG4nut的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


不能在函数体外使用 := 和循环。

NobbZ:

你不能在函数体外使用 := 和循环。

我该如何纠正这个问题?

一个右花括号!

package main

import "fmt"

func main() {
    fmt.Println("hello world")
}

在其他回复中已经有一些剧透和修正后的代码,而且到今天你应该已经知道如何编写一个函数,或者如何将外层作用域中的代码移入函数中。

NobbZ:

你不能在函数体外部使用 := 和循环。

你指的是 onceBody := func() 吗?

有趣的是,当我移除了 fmt.Println("Hello, playground") 并添加了一个闭合大括号后,它就能工作了。 😅

cherilexvold1974:

有趣,当我删除了 fmt.Println(“Hello, playground”) }

这基本上就是我们之前告诉你要做的…

cherilexvold1974:

你指的是 onceBody := func() 吗?

不知道,我只是读了错误信息并快速看了一下提到的那一行。

一旦我看到了问题,我就会把那一行的大部分内容从脑子里丢掉,尤其是当它不是我自己写的代码时。

NobbZ:

另外,到今天你真的应该知道如何编写一个函数了

仍在学习中。我就是这样。我必须说,我正在尽我最大的努力。 尽管我似乎让你感到不快,但我仍然感谢你持续提供的宝贵帮助。

NobbZ:

将代码从外部作用域移入函数

我不明白那是什么意思。

NobbZ:

你不能在函数体外部使用 := 和循环

在那段代码中,函数体具体指什么?它和“作用域”是同一个概念吗?

GonzaSaya:

一个闭合的大括号!

// } 已注释

为什么?

还有,你为什么在那个位置添加了大括号?

package main

import (
	"fmt"
	"sync"
)

func main() {
	fmt.Println("Hello, playground")

	var once sync.Once
	onceBody := func() {
		fmt.Println("Only once")
	}
	done := make(chan bool)
	for i := 0; i < 10; i++ {
		go func() {
			once.Do(onceBody)
			done <- true
		}()
	}
	for i := 0; i < 10; i++ {
		<-done
	}
}

这是由于 main 函数没有正确闭合,导致函数体内容出现在函数 } 符号之后。

建议使用格式化工具来格式化代码,以获得清晰的代码风格。

这个示例代码存在一个关键问题:sync.Once 在循环中被错误地使用。sync.Once 的设计目的是确保某个操作在整个程序生命周期内只执行一次,但示例中每次循环迭代都创建了新的 sync.Once 实例,导致初始化函数被多次执行。

问题代码:

package main

import (
	"fmt"
	"sync"
)

func main() {
	for i := 0; i < 5; i++ {
		var once sync.Once
		once.Do(func() {
			fmt.Println("initialized")
		})
		fmt.Printf("%d\n", i)
	}
}

输出结果:

initialized
0
initialized
1
initialized
2
initialized
3
initialized
4

修正后的正确用法:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var once sync.Once // 将 once 移到循环外部
	
	for i := 0; i < 5; i++ {
		once.Do(func() {
			fmt.Println("initialized")
		})
		fmt.Printf("%d\n", i)
	}
}

正确输出:

initialized
0
1
2
3
4

sync.Once 的正确使用模式是将其声明为包级变量、结构体字段或函数闭包中的共享变量,确保多个调用点共享同一个实例。

回到顶部