猿问

如何使用通道收集来自各种 goroutine 的响应

我是 Golang 的新手,我有一个使用 实现的任务,我WaitGroup想Mutex将其转换为使用Channels。


该任务的一个非常简短的描述是:根据需要拒绝尽可能多的 go 例程来处理结果,并在主 go 例程中等待并收集所有结果。


我使用的实现WaitGroup如下Mutex:


package main


import (

    "fmt"

    "math/rand"

    "sync"

    "time"

)


func process(input int, wg *sync.WaitGroup, result *[]int, lock *sync.Mutex) *[]int {

    defer wg.Done()

    defer lock.Unlock()


    rand.Seed(time.Now().UnixNano())

    n := rand.Intn(5)

    time.Sleep(time.Duration(n) * time.Second)

    lock.Lock()

    *result = append(*result, input * 10)


    return result

}


func main() {


    var wg sync.WaitGroup

    var result []int

    var lock sync.Mutex

    for i := range []int{1,2,3,4,5} {

        wg.Add(1)

        go process(i, &wg, &result, &lock)

    }

}

如何使用Mutexto替换内存同步Channels?


我的主要问题是我不确定如何确定处理最终任务的最终 go 例程,因此让那个成为关闭channel. 这个想法是,通过关闭channel主 go 例程可以循环遍历channel,检索结果,当它看到channel已经关闭时,它继续前进。


在这种情况下,关闭通道的方法也可能是错误的,因此我在这里问。


更有经验的 go 程序员如何使用 解决这个问题channels?


杨魅力
浏览 183回答 3
3回答

牧羊人nacy

这是一个使用WaitGroup而不是等待固定数量的结果的解决方案。package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "math/rand"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")func process(input int, wg *sync.WaitGroup, resultChan chan<- int) {&nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; rand.Seed(time.Now().UnixNano())&nbsp; &nbsp; n := rand.Intn(5)&nbsp; &nbsp; time.Sleep(time.Duration(n) * time.Second)&nbsp; &nbsp; resultChan <- input * 10}func main() {&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; resultChan := make(chan int)&nbsp; &nbsp; for i := range []int{1,2,3,4,5} {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go process(i, &wg, resultChan)&nbsp; &nbsp; }&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; close(resultChan)&nbsp; &nbsp; }()&nbsp; &nbsp; var result []int&nbsp; &nbsp; for r := range resultChan {&nbsp; &nbsp; &nbsp; &nbsp; result = append(result, r)&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println(result)}

慕妹3146593

我更改了您的代码以使用该频道。还有许多其他方法可以使用该频道。package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "math/rand"&nbsp; &nbsp; "time")func process(input int, out chan<- int) {&nbsp; &nbsp; rand.Seed(time.Now().UnixNano())&nbsp; &nbsp; n := rand.Intn(5)&nbsp; &nbsp; time.Sleep(time.Duration(n) * time.Second)&nbsp; &nbsp; out <- input * 10}func main() {&nbsp; &nbsp; var result []int&nbsp; &nbsp; resultChan := make(chan int)&nbsp; &nbsp; items := []int{1, 2, 3, 4, 5}&nbsp; &nbsp; for _, v := range items {&nbsp; &nbsp; &nbsp; &nbsp; go process(v, resultChan)&nbsp; &nbsp; }&nbsp; &nbsp; for i := 0; i < len(items); i++ {&nbsp; &nbsp; &nbsp; &nbsp; res, _ := <-resultChan&nbsp; &nbsp; &nbsp; &nbsp; result = append(result, res)&nbsp; &nbsp; }&nbsp; &nbsp; close(resultChan)&nbsp; &nbsp; fmt.Println(result)}更新:(评论的答案)如果项目数未知,则需要向主发出信号以完成。否则“死锁”,您可以创建一个通道来指示主要功能完成。此外,您可以使用sync.waiteGroup.对于 Goroutine 中的 panic,你可以使用 defer 和 recover 来处理错误。并且您可以创建一个可以使用的错误通道矿石x/sync/errgroup。有很多解决方案。这取决于你的问题。所以没有具体的方式来使用 goroutine、channel 和...

精慕HU

这是一个示例片段,其中我使用通道切片而不是等待组来执行分叉连接:package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "os")type cStruct struct {&nbsp; &nbsp; resultChan chan int&nbsp; &nbsp; errChan&nbsp; &nbsp; chan error}func process(i int) (v int, err error) {&nbsp; &nbsp; v = i&nbsp; &nbsp; return}func spawn(i int) cStruct {&nbsp; &nbsp; r := make(chan int)&nbsp; &nbsp; e := make(chan error)&nbsp; &nbsp; go func(i int) {&nbsp; &nbsp; &nbsp; &nbsp; defer close(r)&nbsp; &nbsp; &nbsp; &nbsp; defer close(e)&nbsp; &nbsp; &nbsp; &nbsp; v, err := process(i)&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e <- err&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; r <- v&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }(i)&nbsp; &nbsp; return cStruct{&nbsp; &nbsp; &nbsp; &nbsp; r,&nbsp; &nbsp; &nbsp; &nbsp; e,&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; //have a slice of channelStruct&nbsp; &nbsp; var cStructs []cStruct&nbsp; &nbsp; nums := []int{1, 2, 3, 4, 5}&nbsp; &nbsp; for _, v := range nums {&nbsp; &nbsp; &nbsp; &nbsp; cStruct := spawn(v)&nbsp; &nbsp; &nbsp; &nbsp; cStructs = append(cStructs, cStruct)&nbsp; &nbsp; }&nbsp; &nbsp; //All the routines have been spawned, now iterate over the slice:&nbsp; &nbsp; var results []int&nbsp; &nbsp; for _, c := range cStructs {&nbsp; &nbsp; &nbsp; &nbsp; rChan, errChan := c.resultChan, c.errChan&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case r := <-rChan:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; results = append(results, r)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; case err := <-errChan:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; os.Exit(1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; //All the work should be done by now, iterating over the results&nbsp; &nbsp; for _, result := range results {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Aggregated result:", result)&nbsp; &nbsp; }}
随时随地看视频慕课网APP

相关分类

Go
我要回答