Golang goroutine 与时间
Golang goroutine with time
我正在学习 Golang 并编写一些示例程序以熟悉不同的概念。
我写了这篇示例文章来了解 go 例程是如何工作的,并 运行 进入这个问题。
我不知道这个程序有什么问题。当 generateOddRandomNumbers() 和 genateEvenRandomNumbers() 的最后一行被注释掉时,它工作得很好。
// time.Sleep(time.Duration(val))
当我在两个函数中取消注释该行时,输出总是错误的。
代码:
package main
import (
"fmt"
"math/rand"
"time"
)
const (
limit = 10000
)
func main() {
rand.Seed(time.Now().UnixNano())
go generateOddRandomNumbers(rand.Intn(9) + 1)
go generateEvenRandomNumbers(rand.Intn(9) + 1)
time.Sleep(1000000)
}
func generateOddRandomNumbers(count int) {
for i := 0; i < count; i++ {
val := rand.Intn(limit)
if val % 2 == 0 {
i--
continue
}
fmt.Printf("Odd[%v/%v] -> %v\n", i + 1, count, val)
// time.Sleep(time.Duration(val))
}
}
func generateEvenRandomNumbers(count int) {
for i := 0; i < count; i++ {
val := rand.Intn(limit)
if val % 2 != 0 {
i--
continue
}
fmt.Printf("Even[%v/%v] -> %v\n", i + 1, count, val)
// time.Sleep(time.Duration(val))
}
}
例如:
良好的输出:Even() 从 1/6 打印到 6/6,Odd() 从 1/3 打印到 3/3
Even[1/6] -> 5202
Even[2/6] -> 2768
Even[3/6] -> 3020
Even[4/6] -> 6386
Even[5/6] -> 8004
Odd[1/3] -> 5075
Odd[2/3] -> 8057
Odd[3/3] -> 9655
Even[6/6] -> 8886
错误输出:(当 time.Sleep() 未注释时)
在下面的例子中,Even 只打印了 1/9 到 3/9(而不是 1/9 到 9/9)
Odd[1/1] -> 4349
Even[1/9] -> 6024
Even[2/9] -> 5444
Even[3/9] -> 6160
有什么想法吗?
Go 程序不会等待您的 go 例程完成。
如果你在 goroutine 中评论 time.Sleep
,你 goroutine 运行 很快,所以你得到一个完整的输出。
如果你在 goroutine 中取消注释 time.Sleep
,你的 goroutine 运行 会很慢。一旦它产生调度程序,主要的 go 程序就完成了,所以你的 goroutine 没有机会完成整个 运行.
您可以使用channel
或sync.WaitGroup
来同步您的程序,例如How to wait for all goroutines to finish in Golang。
顺便说一句,对于time.Sleep(1000000)
,它的单位是ns
,所以在你的例子中主程序很快就退出了。
你的程序退出的原因是因为主线程没有等待生成的 goroutines 完成。你必须保持主线程打开。
一种方法是使用 WaitGroups
。
使用 this 示例的修改版本,您可以执行以下操作:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
const (
limit = 10000
)
func main() {
rand.Seed(time.Now().UnixNano())
var wg sync.WaitGroup
// Add our two items to the wait group
wg.Add(2)
// Call our two items
go generateOddRandomNumbers(rand.Intn(9) + 1, &wg)
go generateEvenRandomNumbers(rand.Intn(9) + 1, &wg)
// Wait for them
wg.Wait()
}
func generateOddRandomNumbers(count int, wg *sync.WaitGroup) {
defer wg.Done();
for i := 0; i < count; i++ {
val := rand.Intn(limit)
if val%2 == 0 {
i--
continue
}
fmt.Printf("Odd[%v/%v] -> %v\n", i+1, count, val)
// time.Sleep(time.Duration(val))
}
}
func generateEvenRandomNumbers(count int, wg *sync.WaitGroup) {
defer wg.Done();
for i := 0; i < count; i++ {
val := rand.Intn(limit)
if val%2 != 0 {
i--
continue
}
fmt.Printf("Even[%v/%v] -> %v\n", i+1, count, val)
// time.Sleep(time.Duration(val))
}
}
/** Which outputs:
Even[1/8] -> 2162
Even[2/8] -> 324
Even[3/8] -> 8388
Even[4/8] -> 7084
Even[5/8] -> 9282
Even[6/8] -> 302
Even[7/8] -> 6232
Even[8/8] -> 8384
Odd[1/3] -> 5063
Odd[2/3] -> 1239
Odd[3/3] -> 7947
*/
我正在学习 Golang 并编写一些示例程序以熟悉不同的概念。 我写了这篇示例文章来了解 go 例程是如何工作的,并 运行 进入这个问题。 我不知道这个程序有什么问题。当 generateOddRandomNumbers() 和 genateEvenRandomNumbers() 的最后一行被注释掉时,它工作得很好。
// time.Sleep(time.Duration(val))
当我在两个函数中取消注释该行时,输出总是错误的。
代码:
package main
import (
"fmt"
"math/rand"
"time"
)
const (
limit = 10000
)
func main() {
rand.Seed(time.Now().UnixNano())
go generateOddRandomNumbers(rand.Intn(9) + 1)
go generateEvenRandomNumbers(rand.Intn(9) + 1)
time.Sleep(1000000)
}
func generateOddRandomNumbers(count int) {
for i := 0; i < count; i++ {
val := rand.Intn(limit)
if val % 2 == 0 {
i--
continue
}
fmt.Printf("Odd[%v/%v] -> %v\n", i + 1, count, val)
// time.Sleep(time.Duration(val))
}
}
func generateEvenRandomNumbers(count int) {
for i := 0; i < count; i++ {
val := rand.Intn(limit)
if val % 2 != 0 {
i--
continue
}
fmt.Printf("Even[%v/%v] -> %v\n", i + 1, count, val)
// time.Sleep(time.Duration(val))
}
}
例如: 良好的输出:Even() 从 1/6 打印到 6/6,Odd() 从 1/3 打印到 3/3
Even[1/6] -> 5202
Even[2/6] -> 2768
Even[3/6] -> 3020
Even[4/6] -> 6386
Even[5/6] -> 8004
Odd[1/3] -> 5075
Odd[2/3] -> 8057
Odd[3/3] -> 9655
Even[6/6] -> 8886
错误输出:(当 time.Sleep() 未注释时) 在下面的例子中,Even 只打印了 1/9 到 3/9(而不是 1/9 到 9/9)
Odd[1/1] -> 4349
Even[1/9] -> 6024
Even[2/9] -> 5444
Even[3/9] -> 6160
有什么想法吗?
Go 程序不会等待您的 go 例程完成。
如果你在 goroutine 中评论
time.Sleep
,你 goroutine 运行 很快,所以你得到一个完整的输出。如果你在 goroutine 中取消注释
time.Sleep
,你的 goroutine 运行 会很慢。一旦它产生调度程序,主要的 go 程序就完成了,所以你的 goroutine 没有机会完成整个 运行.
您可以使用channel
或sync.WaitGroup
来同步您的程序,例如How to wait for all goroutines to finish in Golang。
顺便说一句,对于time.Sleep(1000000)
,它的单位是ns
,所以在你的例子中主程序很快就退出了。
你的程序退出的原因是因为主线程没有等待生成的 goroutines 完成。你必须保持主线程打开。
一种方法是使用 WaitGroups
。
使用 this 示例的修改版本,您可以执行以下操作:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
const (
limit = 10000
)
func main() {
rand.Seed(time.Now().UnixNano())
var wg sync.WaitGroup
// Add our two items to the wait group
wg.Add(2)
// Call our two items
go generateOddRandomNumbers(rand.Intn(9) + 1, &wg)
go generateEvenRandomNumbers(rand.Intn(9) + 1, &wg)
// Wait for them
wg.Wait()
}
func generateOddRandomNumbers(count int, wg *sync.WaitGroup) {
defer wg.Done();
for i := 0; i < count; i++ {
val := rand.Intn(limit)
if val%2 == 0 {
i--
continue
}
fmt.Printf("Odd[%v/%v] -> %v\n", i+1, count, val)
// time.Sleep(time.Duration(val))
}
}
func generateEvenRandomNumbers(count int, wg *sync.WaitGroup) {
defer wg.Done();
for i := 0; i < count; i++ {
val := rand.Intn(limit)
if val%2 != 0 {
i--
continue
}
fmt.Printf("Even[%v/%v] -> %v\n", i+1, count, val)
// time.Sleep(time.Duration(val))
}
}
/** Which outputs:
Even[1/8] -> 2162
Even[2/8] -> 324
Even[3/8] -> 8388
Even[4/8] -> 7084
Even[5/8] -> 9282
Even[6/8] -> 302
Even[7/8] -> 6232
Even[8/8] -> 8384
Odd[1/3] -> 5063
Odd[2/3] -> 1239
Odd[3/3] -> 7947
*/