6
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 的 defer 会被调用来产生:1 2 3 -2 -1

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

是否有一些技巧可以推迟我做错的安置?

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

4

4 回答 4

6

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

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

不,这不是问题,只能通过同时发生(通过实现细节)来解决它。正如在goroutine 的 defer not called when main scope ends中已经暗示的那样。您的代码很活泼,因此您必须显式同步 goroutine。最简单的方法是使用频道或等待组http://golang.org/pkg/sync/#WaitGroup。哪个选项更合适取决于您在做什么。如果您只想等待某个结果,则让 gorutine 在通道上发送其结果,您只需等待它。如果您只想等待多个 goroutine,请使用等待组。

于 2013-11-03T08:56:04.987 回答
2

该过程正在结束,因此内部函数终止。尝试在 main 结束时睡觉:

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。

于 2013-10-27T02:26:39.163 回答
1

是的,问题在于 goroutine 调度并且是平台相关的。在 goroutine 的函数末尾使用runtime.Gosched以确保它获得一些 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

于 2013-10-27T19:53:37.490 回答
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

于 2016-10-18T12:00:12.027 回答