如何运行多个 goroutine 并按照运行顺序收集结果

我有以下代码,它具有双重例程结构:


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

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


杨__羊羊
浏览 239回答 2
2回答

当年话下

给你一个更好的主意。问题是您正在读取单个通道,其中由于您的time.Sleep调用,推送到该通道上的值按任意顺序排列。如果您想同时发出time.Sleep调用来模拟并发的长时间运行的进程,您需要做的是让每个 goroutine 将结果写入一个通道。通过这种方式,您可以遍历阻塞的结果通道的有序列表,直到可以从中读取下一个通道(与此答案中的输出队列相同的想法在多线程管道中维护顺序)名称更改以使事情更容易跟踪:package mainimport(&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "math/rand"&nbsp; &nbsp; "time"&nbsp; &nbsp; "strconv")func main(){&nbsp; &nbsp; var jobs []chan string&nbsp; &nbsp; for i := 0; i<10; i++{&nbsp; &nbsp; &nbsp; &nbsp; job := make(chan string)&nbsp; &nbsp; &nbsp; &nbsp; jobs = append(jobs, job)&nbsp; &nbsp; &nbsp; &nbsp; go testfun(i, job)&nbsp; &nbsp; }&nbsp; &nbsp; for _, result := range jobs {&nbsp; &nbsp; &nbsp; fmt.Println(<-result)&nbsp; &nbsp; }}func testfun(i int, job chan<- string){&nbsp; &nbsp; var innerJobs []chan int&nbsp; &nbsp; time.Sleep(time.Millisecond*time.Duration(int64(rand.Intn(10))))&nbsp; &nbsp; for j := 0; j<10; j++ {&nbsp; &nbsp; &nbsp; &nbsp; innerJob := make(chan int)&nbsp; &nbsp; &nbsp; &nbsp; innerJobs = append(innerJobs, innerJob)&nbsp; &nbsp; &nbsp; &nbsp; go testfun2(j, innerJob)&nbsp; &nbsp; }&nbsp; &nbsp; tempStr := strconv.FormatInt(int64(i),10)+" - "&nbsp; &nbsp; for _, result := range innerJobs {&nbsp; &nbsp; &nbsp; tempStr = tempStr + strconv.FormatInt(int64(<-result),10)&nbsp; &nbsp; }&nbsp; &nbsp; job <- tempStr}func testfun2(j int, innerJob chan<- int){&nbsp; &nbsp; time.Sleep(time.Millisecond*time.Duration(int64(rand.Intn(10))))&nbsp; &nbsp; innerJob <- j}

拉风的咖菲猫

一种不同/更有效的方法是使用切片(或数组)并使用sync.WaitGroup:func main() {&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; out := make([]string, 10)&nbsp; &nbsp; for i := 0; i < len(out); i++ {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go testfun(i, &out[i], &wg)&nbsp; &nbsp; }&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; for i := 0; i < len(out); i++ {&nbsp; &nbsp; &nbsp; &nbsp; a := out[i]&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(a)&nbsp; &nbsp; }}func testfun(i int, outVal *string, wg *sync.WaitGroup) {&nbsp; &nbsp; //........&nbsp; &nbsp; *outVal = tempStr&nbsp; &nbsp; wg.Done()}playground编辑:也更新了 testfun2 的示例,忘记了。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go