go - 如何运行多个 goroutines 并以相同的运行顺序收集结果

标签 go

我有以下代码,它有一个 double-go 例程结构:

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

谁能告诉我如何实现我期望的输出?我是新手,如果解决方案显而易见,请原谅我。我已经找了好几天了。

最佳答案

给你一个更好的主意。问题是您正在读取单个 channel ,其中由于您的 time.Sleep 调用,推送到 channel 的值是任意顺序的。如果您想同时发出 time.Sleep 调用以模拟并发的长时间运行的进程,您需要做的是让每个 goroutine 将结果写入一个 channel 。

通过这种方式,您可以遍历阻塞的结果 channel 的有序列表,直到可以从中读取下一个 channel (与此答案中的输出队列相同的想法 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
}

关于go - 如何运行多个 goroutines 并以相同的运行顺序收集结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32855960/

相关文章:

go - 有没有办法在 context.Context 中列出键?

map - 你如何将 TCP 连接对象传递给其他 Go 模块?

go - 如何通过 go imap 库标记 imap 消息/已删除

json - 从 Go 中的 json 文件中读取多个 json 对象

go - 传递任意结构作为函数参数

go - dlv hugo 挂了

go - 我的Visual Studio代码应用程序不断删除导入的程序包

返回 C.CString 时出现 CGo 段错误

google-app-engine - 如何在 martini 中注入(inject) appengine.Context

parsing - 将 bufio.Scanner 的阅读器包装在 bufio.Reader 中有什么好处吗?