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条)

报告相同问题?