Golang的Go协程并发行为不如预期工作。

huangapple go评论111阅读模式
英文:

Golang go routine concurrency behaviour not working as expected

问题

以下是一个简单的Go示例。我有意省略了错误处理等内容,以使示例变得简短。我有一个简单的for循环,使用go关键字调用writeOutput函数5次,以使函数并发运行。

我期望发生的是在/tmp/目录下创建5个文件,文件内容为test。

实际发生的是没有创建任何文件。

然而,如果我移除go关键字,代码会按预期执行。我可能忽视了一些非常明显的东西。我的背景是像PHP/Ruby这样的动态类型语言,所以刚开始接触Go,无法理解为什么存在go关键字时会创建5个文件。

  1. package main
  2. import (
  3. "os"
  4. "math/rand"
  5. "strconv"
  6. )
  7. func main() {
  8. for i := 0; i < 5; i++ {
  9. go writeOutput()
  10. }
  11. }
  12. func writeOutput() {
  13. filename := strconv.Itoa(rand.Intn(10000))
  14. file, _ := os.Create("/tmp/" + filename)
  15. defer file.Close()
  16. file.WriteString("test")
  17. }
英文:

Below is a simple go example. I have omitted error handling etc intentionally to make the example short. I have a simple for loop calling the writeOutput function 5 times using the go keyword to make the function run concurrently.

What I expect to happen is 5 files are created in /tmp/ with the contents of test.

What happens is that no files are created.

However if I remove the go keyword the code executes as expected. Im overlooking something super obvious. My background is dynamically typed languages like PHP/Ruby so just getting to grips with go and can't understand why 5 files are created when the go keyword exists.

  1. package main
  2. import (
  3. &quot;os&quot;
  4. &quot;math/rand&quot;
  5. &quot;strconv&quot;
  6. )
  7. func main() {
  8. for i := 0; i &lt; 5; i++ {
  9. go writeOutput()
  10. }
  11. }
  12. func writeOutput() {
  13. filename := strconv.Itoa(rand.Intn(10000))
  14. file, _ := os.Create(&quot;/tmp/&quot; + filename)
  15. defer file.Close()
  16. file.WriteString(&quot;test&quot;)
  17. }

答案1

得分: 4

我使用了评论中建议的等待组(wait group)来解决了这个问题。

  1. package main
  2. import (
  3. "math/rand"
  4. "os"
  5. "strconv"
  6. "sync"
  7. )
  8. func main() {
  9. var wg sync.WaitGroup
  10. for i := 0; i < 5; i++ {
  11. wg.Add(1)
  12. go func() {
  13. defer wg.Done()
  14. writeOutput()
  15. }()
  16. }
  17. wg.Wait()
  18. }
  19. func writeOutput() {
  20. filename := strconv.Itoa(rand.Intn(10000))
  21. file, _ := os.Create("/tmp/" + filename)
  22. defer file.Close()
  23. file.WriteString("test")
  24. }

这段代码使用了等待组(wait group)来确保所有的goroutine都执行完毕后再继续执行。在主函数中,我们创建了一个等待组(wait group)并设置计数器为5。然后,使用循环创建了5个goroutine,并在每个goroutine中调用writeOutput函数。在writeOutput函数中,我们生成一个随机的文件名,创建一个文件,并将字符串"test"写入文件中。最后,我们使用defer语句关闭文件。在每个goroutine执行完毕后,我们使用wg.Done()减少计数器的值。最后,我们使用wg.Wait()等待所有的goroutine执行完毕。

英文:

I managed to solve this with a wait group as suggested in the comments.

  1. package main
  2. import (
  3. &quot;math/rand&quot;
  4. &quot;os&quot;
  5. &quot;strconv&quot;
  6. &quot;sync&quot;
  7. )
  8. func main() {
  9. var wg sync.WaitGroup
  10. for i := 0; i &lt; 5; i++ {
  11. wg.Add(1)
  12. go func() {
  13. defer wg.Done()
  14. writeOutput()
  15. }()
  16. }
  17. wg.Wait()
  18. }
  19. func writeOutput() {
  20. filename := strconv.Itoa(rand.Intn(10000))
  21. file, _ := os.Create(&quot;/tmp/&quot; + filename)
  22. defer file.Close()
  23. file.WriteString(&quot;test&quot;)
  24. }

huangapple
  • 本文由 发表于 2016年4月2日 18:26:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/36372062.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定