我有以下代码,它具有双向常规结构:
package main
import(
"fmt"
"math/rand"
"time"
"strconv"
)
func main(){
outchan := make(chan string)
for i:=0;i<10;i++{
go testfun(i, outchan)
}
for i:=0;i<10;i++{
a := <-outchan
fmt.Println(a)
}
}
func testfun(i int, outchan chan<- string){
outchan2 := make(chan int)
time.Sleep(time.Millisecond*time.Duration(int64(rand.Intn(10))))
for j:=0;j<10;j++ {
go testfun2(j, outchan2)
}
tempStr := strconv.FormatInt(int64(i),10)+" - "
for j:=0;j<10;j++ {
tempStr = tempStr + strconv.FormatInt(int64(<-outchan2),10)
}
outchan <- tempStr
}
func testfun2(j int, outchan2 chan<- int){
time.Sleep(time.Millisecond*time.Duration(int64(rand.Intn(10))))
outchan2 <- j
}
我期待的输出是
0 - 0123456789
1 - 0123456789
2 - 0123456789
3 - 0123456789
4 - 0123456789
5 - 0123456789
6 - 0123456789
7 - 0123456789
8 - 0123456789
9 - 0123456789
但我得到了这个:
7 - 7980345261
6 - 4035897621
3 - 9047526831
9 - 4032861975
8 - 9570831624
5 - 3798021546
1 - 0985362471
0 - 1849276035
2 - 9572806143
4 - 5768032419
有谁能告诉我如何实现我期待的输出?我是新手,如果解决方案很明显,请原谅我。我好几天都在寻找它。
答案 0 :(得分:5)
为了给你一个更好的主意。问题在于,您正在阅读单个频道,其中由于您的time.Sleep
来电,推送到频道的值处于任意顺序。如果您想同时发出time.Sleep
个调用来模拟并发的长时间运行进程,那么您要做的就是让每个goroutine写入包含结果的通道。
通过这种方式,您可以迭代结果通道阻塞的有序列表,直到可以读取下一个通道(与此答案Maintaining Order in a Multi-Threaded Pipeline中的输出队列相同)这是您的使用一些名称更改重新编写代码以使事情更容易跟踪:
package main
import(
"fmt"
"math/rand"
"time"
"strconv"
)
func main(){
var jobs []chan string
for i := 0; i<10; i++{
job := make(chan string)
jobs = append(jobs, job)
go testfun(i, job)
}
for _, result := range jobs {
fmt.Println(<-result)
}
}
func testfun(i int, job chan<- string){
var innerJobs []chan int
time.Sleep(time.Millisecond*time.Duration(int64(rand.Intn(10))))
for j := 0; j<10; j++ {
innerJob := make(chan int)
innerJobs = append(innerJobs, innerJob)
go testfun2(j, innerJob)
}
tempStr := strconv.FormatInt(int64(i),10)+" - "
for _, result := range innerJobs {
tempStr = tempStr + strconv.FormatInt(int64(<-result),10)
}
job <- tempStr
}
func testfun2(j int, innerJob chan<- int){
time.Sleep(time.Millisecond*time.Duration(int64(rand.Intn(10))))
innerJob <- j
}
答案 1 :(得分:2)
一种不同/更有效的方法是使用切片(或数组)并使用sync.WaitGroup
:
func main() {
var wg sync.WaitGroup
out := make([]string, 10)
for i := 0; i < len(out); i++ {
wg.Add(1)
go testfun(i, &out[i], &wg)
}
wg.Wait()
for i := 0; i < len(out); i++ {
a := out[i]
fmt.Println(a)
}
}
func testfun(i int, outVal *string, wg *sync.WaitGroup) {
//........
*outVal = tempStr
wg.Done()
}
编辑:更新了testfun2的示例,忘记了这一点。