当主要范围结束时,不会调用goroutine的延迟

时间:2013-10-27 02:11:32

标签: go

package main

import(
    "fmt"
    "time"
)

func main(){
    fmt.Println("1")
    defer fmt.Println("-1")
    go func() { 
        fmt.Println("2")
        defer fmt.Println("-2")
        time.Sleep(9 * time.Second)
    }()
    time.Sleep(1 * time.Second)
    fmt.Println("3")
}

产生输出:1 2 3 -1 但我会认为goroutine的推迟会被称为产生:1 2 3 -2 -1

在我的实际代码中,我的goroutine被阻止在websocket上...我想我可以发送一个关闭信号,但我还没有弄清楚如何做一个等待多对象的事情(如果它实际上可以在go)完成。我正在通过将延迟-2提升到主范围来解决我的问题。

是否有一些推迟放置的技巧我做得不对?

http://play.golang.org/p/qv8UEuF2Rb

4 个答案:

答案 0 :(得分:5)

(我没有足够的代表发表评论?)

  

是的,问题在于goroutine调度并且与平台有关。使用带有goroutine的函数末尾的runtime.Gosched来确保它获得一些cputime。目前在x86_64 linux上,下面的代码将生成“3”但没有Gosched它会生成“1”:

没有。这不是问题,只能通过共同发生来解决(通过实施细节)。正如goroutine's defer not called when main scope ends中已经暗示过的那样。你的代码很活泼,因此你必须明确地同步goroutines。最简单的方法是使用频道或等待组http://golang.org/pkg/sync/#WaitGroup。哪个选项更合适取决于您正在做什么。如果您只想等待一些结果,那么让gorutine将其结果发送到频道,您只需等待它。如果你只是想等待一些goroutine,那就使用一个waitgroup。

答案 1 :(得分:2)

过程结束,因此终止内部功能。尝试在主要结束时睡觉:

func main(){
    fmt.Println("1")
    defer fmt.Println("-1")
    go func() { 
        fmt.Println("2")
        defer fmt.Println("-2")
        time.Sleep(9 * time.Second)
    }()
    time.Sleep(1 * time.Second)
    fmt.Println("3")
    time.Sleep(9 * time.Second)
}

http://play.golang.org/p/Qrtz_0xiRs

编辑:正如评论中所提到的,这不是一般的正确方法。你应该明确地等待goroutine。

答案 2 :(得分:1)

是的,问题在于goroutine计划,并且是platform dependent。使用函数末尾的runtime.Gosched和goroutine来确保它获得一些cputime。目前在x86_64 linux上,下面的代码将生成“3”但没有Gosched它会生成“1”:

q = 1
go func() { 
    q = 2
    defer func() { q = 3 }()
}()
runtime.Gosched()
fmt.Println(q)

http://play.golang.org/p/dNFQv9IxXv

答案 3 :(得分:1)

WaitGroup可以帮助您解决问题:

package main

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

func main(){
    fmt.Println("-start main-")
    defer fmt.Println("-defer main-")

    wg := sync.WaitGroup{}
    wg.Add(1)

    go func() { 
        fmt.Println("-start goroutine-")
        defer fmt.Println("-defer goroutine-")

        time.Sleep(2 * time.Second)
        wg.Done() 
    }()

    fmt.Println("-end main-")
    wg.Wait()
}

打印:

-start main-
-end main-
-start goroutine-
-defer goroutine-
-defer main-

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