为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
杨__羊羊 2021-11-08 19:10:59
我有以下代码,它具有双重例程结构:package mainimport(    "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 - 01234567891 - 01234567892 - 01234567893 - 01234567894 - 01234567895 - 01234567896 - 01234567897 - 01234567898 - 01234567899 - 0123456789但是我得到了这个:7 - 79803452616 - 40358976213 - 90475268319 - 40328619758 - 95708316245 - 37980215461 - 09853624710 - 18492760352 - 95728061434 - 5768032419谁能告诉我如何实现我期望的输出?我是新手,如果解决方案很明显,请原谅我。我已经找了好几天了。
查看完整描述

2 回答

?
当年话下

TA贡献1890条经验 获得超9个赞

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


通过这种方式,您可以遍历阻塞的结果通道的有序列表,直到可以从中读取下一个通道(与此答案中的输出队列相同的想法在多线程管道中维护顺序)名称更改以使事情更容易跟踪:


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

}


查看完整回答
反对 回复 2021-11-08
?
拉风的咖菲猫

TA贡献1995条经验 获得超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()

}

playground


编辑:也更新了 testfun2 的示例,忘记了。


查看完整回答
反对 回复 2021-11-08
  • 2 回答
  • 0 关注
  • 238 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信