同时对切片的所有元素应用计算繁重的操作

问题描述 投票:0回答:1

我有一片

problemArray := []int{77,44,34,752,12}
我必须对切片的所有元素执行计算繁重的操作幸运的是我可以同时执行操作假设我的函数如下

func ComputeHeavyOperation(num int) int {
     time.Sleep(time.Second * 2)
     return num * 2

我想得到这样的回应

output := SomeNewFunc(problemArray, ComputeHeavyOperation)
fmt.Println(output)

输出会像

{144,88,68,1504,24}
写 SomeNewFunc 的问题,或者如果我以错误的方式做它可能是任何其他方式。

这是我试过的

package main

import (
    "fmt"
    "time"
)

func mathematicalCompute(container []int, c chan int) {
    for _, n := range container {
        go func(ch chan int) {
            time.Sleep(time.Second * 2)
            ch <- n * 2
        }(c)
    }
    defer close(c)
}
func main() {
    fmt.Println("Hello World")
    nums := []int{1, 2, 3, 4, 5}
    c := make(chan int)
    mathematicalCompute(nums, c)
    for result := range c {
        fmt.Println(result)
    }

}

它只输出

Hello World

我认为频道甚至在接收之前就已经关闭了,我注释掉了

defer close(c)
,它给出了以下输出

10
10
10
10
10
[T+2000ms]
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
    /tmp/sandbox3588770438/prog.go:21 +0xdb```

go channel goroutine
1个回答
0
投票

您当前实现的问题是您正在为切片中的每个元素创建一个新的 goroutine,但您没有等待这些 goroutines 在关闭通道之前完成。这意味着通道关闭得太早,导致死锁。

这个问题的一个解决方案是使用等待组来同步 goroutines 并确保它们在关闭通道之前都已完成。这是使用等待组的代码的更新版本:

package main

import (
    "fmt"
    "sync"
    "time"
)

func mathematicalCompute(container []int, c chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for _, n := range container {
        time.Sleep(time.Second * 2)
        c <- n * 2
    }
}

func SomeNewFunc(container []int, f func(int) int) []int {
    c := make(chan int)
    var wg sync.WaitGroup
    wg.Add(len(container))
    go mathematicalCompute(container, c, &wg)
    go func() {
        wg.Wait()
        close(c)
    }()
    var results []int
    for n := range c {
        results = append(results, f(n))
    }
    return results
}

func ComputeHeavyOperation(num int) int {
    time.Sleep(time.Second * 2)
    return num * 2
}

func main() {
    nums := []int{77, 44, 34, 752, 12}
    output := SomeNewFunc(nums, ComputeHeavyOperation)
    fmt.Println(output)
}

mathematicalCompute 函数现在将等待组作为参数,用于在所有 goroutine 完成时发出信号。我们在启动 goroutines 之前将 goroutines 的数量添加到等待组中,然后在单独的 goroutine 中调用 wg.Wait() 阻塞,直到所有 goroutines 完成。一旦发生这种情况,我们就可以安全地关闭通道了。

在 SomeNewFunc 函数中,我们在一个单独的 goroutine 中启动 mathematicalCompute 函数,然后启动另一个 goroutine 等待等待组发出信号并关闭通道。最后,我们在通道上循环读取结果并应用重操作函数,并将结果作为切片返回。

这段代码应该给你你正在寻找的输出。

希望有帮助

© www.soinside.com 2019 - 2024. All rights reserved.