Golang中Goroutines不总是有效的问题探讨
Golang中Goroutines不总是有效的问题探讨 Go by Example: Goroutines
我一直在尝试通过这个学习Go语言,但在Playground上运行代码时得到的结果是:
直接:0 直接:1 直接:2 完成
Go协程类似于C语言中的fork吗?
我猜测是程序在Go函数执行完成前就结束了。
我添加了一个打印语句并改变了结果:
fmt.Println("test")
在–go f(“goroutine”)之前
直接:0 直接:1 直接:2 测试 执行中 协程:0 协程:1 协程:2 完成
可能需要说明示例页面上显示的结果可能不总是那样
更多关于Golang中Goroutines不总是有效的问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢各位。我会继续努力的。之前我一直在通过gobyexample学习基础知识,之后会尝试写一些代码。虽然希望能慢慢学习,但可能还是会遇到一些困难。不过刚开始尝试的内容应该都不会太复杂。
更多关于Golang中Goroutines不总是有效的问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我并非刚开始学习并发编程,但也算不上专家。过去我处理过多线程程序并写过一些相关代码,但那已经是多年前的事了。这就是为什么我会问Go语言中的"go"是否类似于C语言中的"fork"。
另外我认为,既然这是一个学习网站,您可能需要说明实际结果可能与所述内容有所差异。
Go 语法确实更接近 C。
你可能需要解释结果可能与所述情况有所不同
在并发中,协程在不同的时间点启动,需要时间来初始化和执行某些操作。在此期间,程序会继续执行,稍后你才能看到协程的结果。并发中没有默认或保证的顺序,因此如果你按某种顺序启动几个协程,结果可能不会遵循该顺序。此外,并发并不等同于并行。
我同意George所说的。
我之前也有使用fork()系统调用进行多进程处理以及使用POSIX线程进行多线程编程的经验。这些经验帮助我理解了许多并发的核心概念。所以我认为你有一个很好的起点。
Go语言中的并发远不止这些,你需要学习Go语言是如何实现并发的,以及通道的用法——通道用于goroutine间的通信,包括数据传输和信号传递。
有很多优质的学习资源,包括各种Go语言书籍中的相关章节、专门讲解并发的书籍《Concurrency in Go》、视频课程中的教学内容(我认为@William Kennedy的《Ultimate Go》非常出色),还有YouTube上的视频。当你掌握了基础知识后,可以尝试搜索关于Go并发模式的视频。
func main() {
fmt.Println("hello world")
}
在Go语言中,Goroutines的调度是非确定性的,这可能导致执行顺序与预期不符。你的观察是正确的:程序可能在Goroutines完成前就退出了。这通常是因为主Goroutine(main函数)结束时,所有其他Goroutines会被强制终止,无论它们是否执行完毕。
Goroutines与C语言中的fork有本质区别。C的fork创建的是独立的进程,拥有各自的内存空间;而Goroutines是轻量级线程,由Go运行时管理,共享内存空间,通过通道(channels)或同步原语(如sync.WaitGroup)进行通信和协调。
在Go by Example的代码中,缺少同步机制是导致输出不一致的原因。以下是一个修正版本,使用sync.WaitGroup确保所有Goroutines完成后再退出:
package main
import (
"fmt"
"sync"
)
func f(from string, wg *sync.WaitGroup) {
defer wg.Done() // 通知WaitGroup此Goroutine完成
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
}
func main() {
var wg sync.WaitGroup
wg.Add(1) // 增加一个等待的Goroutine
go f("goroutine", &wg)
wg.Add(1)
go f("direct", &wg)
wg.Wait() // 等待所有Goroutines完成
fmt.Println("done")
}
在这个示例中,sync.WaitGroup用于跟踪Goroutines的完成状态。wg.Add(1)在启动每个Goroutine前增加计数,defer wg.Done()在每个Goroutine结束时减少计数,wg.Wait()会阻塞直到计数为零。这确保了"done"在所有输出后打印。
输出顺序可能仍因调度而变,但所有Goroutines都会执行完毕。例如,可能输出:
direct : 0
direct : 1
direct : 2
goroutine : 0
goroutine : 1
goroutine : 2
done
或
goroutine : 0
direct : 0
goroutine : 1
direct : 1
goroutine : 2
direct : 2
done
在Go Playground上,由于环境限制,Goroutines的行为可能更不可预测,但添加同步机制是解决此类问题的标准方法。



