有没有办法阻止长时间阻塞功能?

bru*_*oqc 9 go

我有一个运行几分钟的功能,我正试图找到一种方法来阻止它使用一个频道.

我想我不能像我在下面的代码那样做,因为我认为select只会stopdefault完成之后处理这个案例.

package main

import (
    "fmt"
    "time"
)

func main() {
    stop := make(chan int)

    go func() {
        for {
            select {
            case <-stop:
                fmt.Println("return")
                return
            default:
                fmt.Println("block")
                time.Sleep(5 * time.Second) // simulate a long running function
                fmt.Println("unblock")
            }
        }
    }()

    time.Sleep(1 * time.Second)
    stop <- 1
}
Run Code Online (Sandbox Code Playgroud)

kos*_*tix 7

我认为你不能这样做:Go中的goroutines在某种意义上是合作的:直到goroutine 积极地试图弄清楚它是否应该退出,没有办法强迫它这样做.

事实上,我认为这是一个功能,因为如果你可以强行收获一个长期运行的goroutine,你将无法确定它是否干净利落,即正确释放它所获得的所有资源.

所以要么就是这样(例如,如果你的过程想要退出,只需等待那个goroutine完成)或重组它,以便它定期检查是否有信号退出.或者甚至考虑将它执行的任务卸载到外部进程(但请注意,虽然在释放从操作系统获取的资源方面杀死进程是安全的,但对于可能已更新的进程的外部数据而言,这是不安全的 - 比如文件).


Lar*_*tle 6

我不认为你可以结束一个 goroutine,但你可以切换到另一个 goroutine。您可以通过将函数包装在 goroutine 中来超时函数,该 goroutine 在完成后将数据发送到通道。然后需要选择等待返回的频道或超时的频道。

例子:

package main

import (
    "fmt"
    "time"
)

func waitForMe(){
        time.Sleep(time.Second*5)
}
func main(){
        c1 := make(chan string, 1)
        go func(){
                waitForMe()
                c1 <- "waitForMe is done"
        }()
        select {
        case res := <-c1:
                fmt.Println(res)
        case <-time.After(time.Second*2):
                fmt.Println("timed out")
        }
}
Run Code Online (Sandbox Code Playgroud)

注意:每次通话时间selecttime.After()或有阻塞通道,如果可能的话够程切换到下一个可用的goroutine。

这是您的程序发生的情况。

带有 Goroutine 语句的程序

package main

import (
    "fmt"
    "time"
)

func main() {
    stop := make(chan int)
    go func() {
       fmt.Println("Goroutine B before for loop")
        for {
            fmt.Println("Goroutine B inside for loop")
            select {
            case <-stop:
                fmt.Println("return")
                return
            default:
                fmt.Println("Goroutine B default case")
                fmt.Println("block")
                time.Sleep(5 * time.Second) // simulate a long running function
                fmt.Println("unblock")
            }
        }
    }()

    fmt.Println("Goroutine A before time.Sleep()")
    time.Sleep(1 * time.Second)
    fmt.Println("Goroutine A after sleep")
    stop <- 1
    fmt.Println("Goroutine A after stop")
}
Run Code Online (Sandbox Code Playgroud)

输出

Goroutine A before time.Sleep()
Goroutine B before for loop
Goroutine B inside for loop
Goroutine B default case
block
Goroutine A after sleep
unblock
Goroutine B inside for loop
return
Goroutine A after stop
Run Code Online (Sandbox Code Playgroud)

有用的链接:https : //gobyexample.com/timeouts