doushen8391 2014-11-07 16:25
浏览 46
已采纳

动态创建goroutine的最佳方法是什么?

Sorry if this is a newb question but I'm a newb ;). I have the following playground. How do I create my goroutines dynamically? My first set in the playground works as expected but my second set returns "11" for each value. I can solve it by uncommenting line 38 but that seems kind of like a hack. Is there a more preferred way to create my goroutines dynamically?

package main

import (
    "fmt"
    "log"
    "time"
)

func myFunc(i int) int {
    return i
}

func first() {
    firstChannel := make(chan int)
    go func() { firstChannel <- myFunc(0) }()
    go func() { firstChannel <- myFunc(1) }()
    go func() { firstChannel <- myFunc(2) }()
    go func() { firstChannel <- myFunc(3) }()
    go func() { firstChannel <- myFunc(4) }()
    go func() { firstChannel <- myFunc(5) }()
    go func() { firstChannel <- myFunc(6) }()
    go func() { firstChannel <- myFunc(7) }()
    go func() { firstChannel <- myFunc(8) }()
    go func() { firstChannel <- myFunc(9) }()
    go func() { firstChannel <- myFunc(10) }()

    for k := 0; k < 11; k++ {
        select {
        case result := <-firstChannel:
            log.Println(result)
        }
    }
}
func second() {
    secondChannel := make(chan int)
    for j := 0; j < 11; j++ {
        go func() { secondChannel <- myFunc(j) }()
        //time.Sleep(1*time.Millisecond)
    }
    for k := 0; k < 11; k++ {
        select {
        case result := <-secondChannel:
            log.Println(result)
        }
    }
}

func main() {
    fmt.Println("First set------------------")
    first()
    time.Sleep(1 * time.Second)
    fmt.Println("Second set------------------")
    second()
}

Result:

First set------------------
2009/11/10 23:00:00 0
2009/11/10 23:00:00 1
2009/11/10 23:00:00 2
2009/11/10 23:00:00 3
2009/11/10 23:00:00 4
2009/11/10 23:00:00 5
2009/11/10 23:00:00 6
2009/11/10 23:00:00 7
2009/11/10 23:00:00 8
2009/11/10 23:00:00 9
2009/11/10 23:00:00 10
Second set------------------
2009/11/10 23:00:01 11
2009/11/10 23:00:01 11
2009/11/10 23:00:01 11
2009/11/10 23:00:01 11
2009/11/10 23:00:01 11
2009/11/10 23:00:01 11
2009/11/10 23:00:01 11
2009/11/10 23:00:01 11
2009/11/10 23:00:01 11
2009/11/10 23:00:01 11
2009/11/10 23:00:01 11
  • 写回答

2条回答 默认 最新

  • dry69034 2014-11-07 16:42
    关注

    The Go Programming Language Specification

    Function literals

    Function literals are closures: they may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long as they are accessible.

    What happens with closures running as goroutines?

    Some confusion may arise when using closures with concurrency.

    To bind the current value of v to each closure as it is launched, one must modify the inner loop to create a new variable each iteration. One way is to pass the variable as an argument to the closure.

    Even easier is just to create a new variable, using a declaration style that may seem odd but works fine in Go.

    See Captured Closure (for Loop Variable) in Go.

    Use j := j. For example,

    package main
    
    import (
        "fmt"
        "log"
        "time"
    )
    
    func myFunc(i int) int {
        return i
    }
    
    func first() {
        firstChannel := make(chan int)
        go func() { firstChannel <- myFunc(0) }()
        go func() { firstChannel <- myFunc(1) }()
        go func() { firstChannel <- myFunc(2) }()
        go func() { firstChannel <- myFunc(3) }()
        go func() { firstChannel <- myFunc(4) }()
        go func() { firstChannel <- myFunc(5) }()
        go func() { firstChannel <- myFunc(6) }()
        go func() { firstChannel <- myFunc(7) }()
        go func() { firstChannel <- myFunc(8) }()
        go func() { firstChannel <- myFunc(9) }()
        go func() { firstChannel <- myFunc(10) }()
    
        for k := 0; k < 11; k++ {
            select {
            case result := <-firstChannel:
                log.Println(result)
            }
        }
    }
    func second() {
        secondChannel := make(chan int)
        for j := 0; j < 11; j++ {
            j := j
            go func() { secondChannel <- myFunc(j) }()
            //time.Sleep(1*time.Millisecond)
        }
        for k := 0; k < 11; k++ {
            select {
            case result := <-secondChannel:
                log.Println(result)
            }
        }
    }
    
    func main() {
        fmt.Println("First set------------------")
        first()
        time.Sleep(1 * time.Second)
        fmt.Println("Second set------------------")
        second()
    }
    

    Output:

    First set------------------
    2009/11/10 23:00:00 0
    2009/11/10 23:00:00 1
    2009/11/10 23:00:00 2
    2009/11/10 23:00:00 3
    2009/11/10 23:00:00 4
    2009/11/10 23:00:00 5
    2009/11/10 23:00:00 6
    2009/11/10 23:00:00 7
    2009/11/10 23:00:00 8
    2009/11/10 23:00:00 9
    2009/11/10 23:00:00 10
    Second set------------------
    2009/11/10 23:00:01 0
    2009/11/10 23:00:01 1
    2009/11/10 23:00:01 2
    2009/11/10 23:00:01 3
    2009/11/10 23:00:01 4
    2009/11/10 23:00:01 5
    2009/11/10 23:00:01 6
    2009/11/10 23:00:01 7
    2009/11/10 23:00:01 8
    2009/11/10 23:00:01 9
    2009/11/10 23:00:01 1
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 fcloudflare域名已经用了一年了,突然之间finalshell证书签发错误怎么解决
  • ¥15 近端策略优化 PPO | 损失值计算问题
  • ¥20 高通移动端,安卓12,如何让wifi无视国家码启动6Gwifi,重新开机无需干涉自动连接
  • ¥15 Hadoop实训论文成品! 任意标题 价格可私 急
  • ¥15 程序实在不会写,要秃了
  • ¥15 pycharm导入不了自己的包
  • ¥15 本人本科机械,目前研一。没有深度学习基础,目前对研究生课题一片迷茫,请教各位!
  • ¥15 关于R语言单因素与多因素线性回归的平均值
  • ¥15 服务器清除BIOS之后引导不了
  • ¥15 CPLEX用OPL编写的混合整数线性优化问题。