英文:
Why is my supposedly parallel go program not parallel
问题
你遇到的问题是输出没有按照你期望的顺序混合输出,而是先输出完字母再输出数字。这是因为在Go语言中,goroutine的执行顺序是不确定的,它们是并发执行的。在你的代码中,你创建了两个goroutine,一个用于输出字母,一个用于输出数字。由于goroutine的执行顺序是不确定的,所以有可能先执行完输出字母的goroutine,然后再执行输出数字的goroutine,这样就导致了输出的顺序不是你期望的混合输出。
如果你希望输出的顺序是混合的,你可以使用其他的同步机制来控制goroutine的执行顺序,比如使用channel或者互斥锁。这样可以确保在一个goroutine执行完之前,另一个goroutine不会开始执行。
以下是使用channel来控制goroutine执行顺序的修改后的代码:
package main
import (
"fmt"
"runtime"
)
func alphabets(ch chan bool) {
for char := 'a'; char < 'a'+26; char++ {
fmt.Printf("%c ", char)
}
ch <- true //发送信号表示字母输出完成
}
func numbers(ch chan bool) {
for number := 1; number < 27; number++ {
fmt.Printf("%d ", number)
}
ch <- true //发送信号表示数字输出完成
}
func main() {
runtime.GOMAXPROCS(2)
ch1 := make(chan bool)
ch2 := make(chan bool)
fmt.Println("Starting Go Routines")
go alphabets(ch1)
go numbers(ch2)
fmt.Println("\nWaiting To Finish")
<-ch1 //等待字母输出完成
<-ch2 //等待数字输出完成
fmt.Println("\nTerminating Program")
}
这样修改后,通过使用channel来进行同步,可以确保在一个goroutine执行完之前,另一个goroutine不会开始执行,从而实现了混合输出的效果。
英文:
package main
import (
"fmt"
"runtime"
"sync"
)
var wg sync.WaitGroup
func alphabets() {
for char := 'a'; char < 'a'+26; char++ {
fmt.Printf("%c ", char)
}
wg.Done() //decrement number of goroutines to wait for
}
func numbers() {
for number := 1; number < 27; number++ {
fmt.Printf("%d ", number)
}
wg.Done()
}
func main() {
runtime.GOMAXPROCS(2)
wg.Add(2) //wait for two goroutines
fmt.Println("Starting Go Routines")
go alphabets()
go numbers()
fmt.Println("\nWaiting To Finish")
wg.Wait() //wait for the two goroutines to finish executing
fmt.Println("\nTerminating Program")
}
I expect the output to be mixed up(for lack of a better word), but instead; a sample output is:
$ go run parallel_prog.go
Starting Go Routines
Waiting To Finish
a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
Terminating Program
What I'm I missing?
Thanks,
答案1
得分: 6
你没有错。它是有效的。调用没有显示为“交错”(混合),不是因为它们没有并行化,而是因为它们发生得非常快。
你可以轻松地添加一些对time.Sleep
的调用,以更好地观察并行化。通过睡眠,我们可以确保打印alphabets
和numbers
应该是交错的。
以下是带有Sleep
调用的程序,以“强制”交错:
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func alphabets() {
defer wg.Done()
for char := 'a'; char < 'a'+26; char++ {
fmt.Printf("%c ", char)
time.Sleep(time.Second * 2)
}
}
func numbers() {
defer wg.Done()
for number := 1; number < 27; number++ {
fmt.Printf("%d ", number)
time.Sleep(time.Second * 3)
}
}
func main() {
fmt.Println("Starting Go Routines")
wg.Add(2)
go alphabets()
go numbers()
fmt.Println("\nWaiting To Finish")
wg.Wait()
fmt.Println("\nTerminating Program")
}
注意:
你可能已经知道这一点,但设置GOMAXPROCS
对于是否并行执行此示例没有任何影响,只影响它消耗多少资源。
GOMAXPROCS设置控制操作系统线程尝试同时执行代码的数量。例如,如果GOMAXPROCS为4,则程序一次只会在4个操作系统线程上执行代码,即使有1000个goroutine。此限制不计算在系统调用(如I/O)中被阻塞的线程。
英文:
You're missing nothing. It's working. The calls aren't showing up "interlaced" (mixed up) not because they're not being parallelized, but because they're happening really fast.
You can easily add some calls to time.Sleep
to see the parallelization better. By sleeping, we know 100% that printing alphabets
and numbers
should be interlaced.
Your program with Sleep
calls to "force" interlacing
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func alphabets() {
defer wg.Done()
for char := 'a'; char < 'a'+26; char++ {
fmt.Printf("%c ", char)
time.Sleep(time.Second * 2)
}
}
func numbers() {
defer wg.Done()
for number := 1; number < 27; number++ {
fmt.Printf("%d ", number)
time.Sleep(time.Second * 3)
}
}
func main() {
fmt.Println("Starting Go Routines")
wg.Add(2)
go alphabets()
go numbers()
fmt.Println("\nWaiting To Finish")
wg.Wait()
fmt.Println("\nTerminating Program")
}
Note
You probably already know this, but setting GOMAXPROCS
doesn't have any effect on whether or not this example is executed in parallel, just how many resources it consumes.
> The GOMAXPROCS setting controls how many operating systems threads attempt to execute code simultaneously. For example, if GOMAXPROCS is 4, then the program will only execute code on 4 operating system threads at once, even if there are 1000 goroutines. The limit does not count threads blocked in system calls such as I/O.
Source: Go 1.5 GOMAXPROCS Default
答案2
得分: 3
你是否在使用Go Playground?当我在本地运行你的代码时,我得到的结果是:
启动Go协程
等待完成
1 2 3 4 5 6 7 8 9 10 11 12 a 13 14 15 16 17 b 18 19 c 20 21 d 22 23 e 24 25 f 26 g h i j k l m n o p q r s t u v w x y z
终止程序
Playground是确定性的。Goroutines不会频繁切换,并且不会在多个线程中运行。
英文:
Are you using the Go playground by any chance? When I run your code locally, I get:
Starting Go Routines
Waiting To Finish
1 2 3 4 5 6 7 8 9 10 11 12 a 13 14 15 16 17 b 18 19 c 20 21 d 22 23 e 24 25 f 26 g h i j k l m n o p q r s t u v w x y z
Terminating Program
The playground is deterministic in nature. Goroutines don't yield as often and don't run in multiple threads.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论