Goroutines行为

时间:2016-06-24 12:42:08

标签: go

例如我有这段代码:

func main() {
    go myRoutine(1, channel)
    go myRoutine(2, channel)
    go myRoutine(3, channel)
    go myRoutine(4, channel)

    for i := 0; i < 4; i++ {
        fmt.Println("Returned routine:", <-channel)
    }
}

func myRoutine(chnum int, c chan int) {
    //doing some stuff here
    c <- chnum
    //and doing some stuff here
}

我希望myRoutine在写入频道后立即退出。 谷歌告诉我,如果我要退出我的goroutine,我应该有关机频道和信号。 我想知道在с&lt; - chnum?

之后添加回报是不够的

关于goroutines的第二个问题: 当我启动我的应用程序时,它创建了4个进程(每个CPU核心一个),我的例程再添加两个。我是否应该在完成goroutines之后做一些事情来杀死这两个过程,或者Go自己做了什么?

2 个答案:

答案 0 :(得分:1)

在“с&lt; - chnum”之后添加“return”语句是不够的。那是因为通道将阻塞,直到信息可以插入通道。此外,您需要考虑可能需要缓冲通道,以便可以从线程中插入和检索多个条目。考虑下面的代码,它使用缓冲的通道:

package main

import "fmt"

func main() {

    numGoRountines :=  10
    c := make(chan int, numGoRountines)

    for i := 0; i < numGoRountines; i++ {
        go myRoutine(i, c)
    }

    for i := 0; i < numGoRountines; i++ {
        fmt.Println("Returned routine:", <-c)
    }
}

func myRoutine(chnum int, c chan int) {
    //doing some stuff here
    c <- chnum
    //and doing some stuff here
}

可能的输出:

Returned routine: 9
Returned routine: 0
Returned routine: 1
Returned routine: 2
Returned routine: 3
Returned routine: 4
Returned routine: 5
Returned routine: 6
Returned routine: 7
Returned routine: 8

关于你的第二个问题,go会为你清理那些额外的goroutine。但请注意,如果父级死亡,子线程也会死亡。您可以在下面看到一个示例:

package main

import (
    "fmt"
    "sync"
)

func main() {

    var waitGroupOnlyForParents sync.WaitGroup

    numGoRountines :=  4

    for i := 0; i < numGoRountines; i++ {
        waitGroupOnlyForParents.Add(1)
        go myRoutine(&waitGroupOnlyForParents, i)
    }

    // makes main function waits for every one who calls the method Done() in our wait group
    waitGroupOnlyForParents.Wait()
}

func myRoutine(wg *sync.WaitGroup, myId int) {
    defer wg.Done()

    numGoRountines := 2
    for i := 0; i < numGoRountines; i++ {
        go anotherRoutine(myId, i)
    }
}
func anotherRoutine( parentId, childId int){
    fmt.Printf("Created by %d, my name is %d\n", parentId, childId)
}

可能的输出:

Created by 3, my name is 1
Created by 0, my name is 1
Created by 1, my name is 1

现在假设我们希望同步所有线程,以确保每个线程都能完成所需的一切,我们会稍微更改代码:

package main

import (
    "fmt"
    "sync"
)

func main() {

    var waitGroupForAllThreads sync.WaitGroup

    numGoRountines :=  4

    for i := 0; i < numGoRountines; i++ {
        waitGroupForAllThreads.Add(1)
        go myRoutine(&waitGroupForAllThreads, i)
    }

    // makes main function waits for every one who calls the method Done() in our wait group
    waitGroupForAllThreads.Wait()
}

func myRoutine(wg *sync.WaitGroup, myId int) {
    defer wg.Done()

    numGoRountines := 2
    for i := 0; i < numGoRountines; i++ {
        wg.Add(1)
        go anotherRoutine(wg, myId, i)
    }
}
func anotherRoutine(wg *sync.WaitGroup, parentId, childId int){
    defer wg.Done()
    fmt.Printf("Created by %d, my name is %d\n", parentId, childId)
}

可能的输出(在这种情况下,肯定会显示所有打印件,订单可能会更改):

Created by 3, my name is 1
Created by 0, my name is 1
Created by 1, my name is 1
Created by 2, my name is 1
Created by 3, my name is 0
Created by 0, my name is 0
Created by 1, my name is 0
Created by 2, my name is 0

答案 1 :(得分:1)

  

我想知道在с&lt; - chnum?

之后添加回报是不够的

确实如此。在goroutine中调用return将定义它 只是不要忘记close您的频道。

  

关于goroutines的第二个问题:当我启动我的应用程序时,它会创建4个进程(每个cpu核心一个),我的例程再添加两个进程。在完成goroutines之后我应该做些什么来杀死这两个过程,或者Go自己做了什么?

Goroutines不会产生额外的进程,它们是Go运行时内部的东西。当Go应用程序完成它的工作时,您的操作系统应该正确清理所有内容。