【问题标题】:Go-routines with channels not running parallely通道不并行运行的 Go-routines
【发布时间】:2021-09-09 20:36:24
【问题描述】:
package main
import "time"
func main() {
    stringCh := make(chan func() (string))
    go func() {
        stringCh <- func() (string) {
            return stringReturner()
        }
        close(stringCh)
    }()

    intCh := make(chan func() (int))
    go func() {
        intCh <- func() (int) {
            return intReturner()
        }
        close(intCh)
    }()

    str := (<-stringCh)()
    print("Printing str: ", str,"\n\n")
    num := (<-intCh)()
    print("Printing int: ", num,"\n\n")     
}

func intReturner()int{
    time.Sleep(5 * time.Second)
    print("Inside int returner\n\n");
    return 1;
}

func stringReturner()string{
    time.Sleep(5 * time.Second)
    print("Inside string returner\n\n");
    return "abcd";
}

输出:

内部字符串返回器

打印字符串:abcd

等待 5 秒

int 返回器内部

打印整数:1

https://play.golang.org/p/oE2ybs7Jo-W

为什么这个编码需要 10 秒而不是 5 秒来执行?我们通过正确生成两个 go-routines 来并行化调用(1 个用于 string returner,1 个用于 int returner),但为什么 int returner 在 string returner 执行后执行?

【问题讨论】:

  • 虽然下面的答案在技术上是正确的,但关键的见解是“从 func 的 chan 中读取 func 值”和“执行 func”之间的区别。通常并发代码的结构是 goroutine 直接将值写入 chan(而不是生成值的 func)。

标签: go parallel-processing goroutine


【解决方案1】:

通道正在以睡眠方式返回函数,并且该函数以顺序方式调用。这就是为什么一般需要 10 秒。

https://play.golang.org/p/UpHD7Ttw03R

【讨论】:

  • 哦,我明白了,所以你的意思是说,我们从通道读取时,我们在每个函数中执行睡眠,需要 5+5 秒?
  • 是的,因为底层函数是按顺序调用的,但不是 goroutine 的一部分。我在上述操场的 goroutine 中移动睡眠函数调用。
  • 这是为什么呢?是否有一个原因?因为我在想,睡眠应该对两者并行发生,然后才将值返回到各自的通道。 (理想情况下,这也应该同时发生)
  • play.golang.org/p/VV-fFUza52W 我已经取消了睡眠,我们仍然可以看到这里的 for 循环按顺序执行。
  • 如果 intReturner 和 stringReturner 被并行调用,睡眠应该并行发生。在原来的sn-p中,(
【解决方案2】:

那是因为您只是并行写入通道。但是从频道中读取数据是一个接一个地发生的。要解决此问题,您可以从单独的 go 例程中读取两个通道

var wg sync.WaitGroup
wg.Add(2)
go func() {
  defer wg.Done()
  str := (<-stringCh)()
  print("Printing str: ", str, "\n\n")
}()
go func() {
  defer wg.Done()
  num := (<-intCh)()
  print("Printing int: ", num, "\n\n")
}()
wg.Wait()

【讨论】:

  • 阅读的顺序有什么影响?我同意它们是按顺序发生的,但它们不应该只是读取 go-routines 执行的函数的结果吗?由于这些功能是并行发生的,即两者的睡眠 5 秒也应该并行发生,对吗?
  • 前 2 个 go 例程实际上并没有调用函数。他们只是将功能排入频道。函数的实际“调用”发生在您执行(&lt;-stringCh)()(&lt;-intCh)() 时。那就是睡眠发生的时候。这些睡眠是按顺序发生的。
【解决方案3】:

根据将 sleep 方法移动到 goroutine 以在 5 秒内同时运行这两个函数的建议:

package main

import "time"

func main() {
    stringCh := make(chan func() string)
    go func() {
        time.Sleep(5 * time.Second)
        stringCh <- func() string {
            return stringReturner()
        }
        close(stringCh)
    }()

    intCh := make(chan func() int)
    go func() {
        time.Sleep(5 * time.Second)
        intCh <- func() int {
            return intReturner()
        }
        close(intCh)
    }()

    str := (<-stringCh)()
    print("Printing str: ", str, "\n\n")
    num := (<-intCh)()
    print("Printing int: ", num, "\n\n")
}

func intReturner() int {
    print("Inside int returner\n\n")
    return 1
}

func stringReturner() string {
    print("Inside string returner\n\n")
    return "abcd"
}

输出:

Inside string returner

Printing str: abcd

Inside int returner

Printing int: 1

【讨论】:

    猜你喜欢
    • 2014-10-11
    • 1970-01-01
    • 1970-01-01
    • 2021-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    相关资源
    最近更新 更多