繁体   English   中英

信号goroutines在通道关闭时停止

[英]Signal goroutines to stop with channel close

我有两个select两个通道的goroutine:一个chan提供数据,一个chan用于信号(完成/退出通道的类型)。

我使用信号通道捕获信号(杀死)并优雅地关闭goroutines。

我从package a运行'worker'goroutines,而捕获信号的goroutine func从package b运行。

我使用来自https://gist.github.com/reiki4040/be3705f307d3cd136e85的信号包。

package a

import "sync"

WorkChan := make(chan int)
QuitChan := make(chan struct{})

func Stop() {
        fmt.Println("Stop called, closing channel")
        close(QuitChan)
}

func Work(wg *sync.WaitGroup) {
    var item int
    for {
        select {
        case item = <- WorkChan:
            ... processing
        case <- QuitChan:
            wg.Done()
            return
        }
    }
}

用于捕获信号的goroutine,并调用a.Stop()

package b

import (
    "os/signal"
    "os"
    "syscal"
    "a"
)

func Signal() {

    sChan := make(chan os.Signal, 1)
    signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGINT)

    for {
        s := <-sChan
        switch s {
        case os.Interrupt, syscall.SIGTERM:
            a.Stop()
        }
    }
}

这是我的主要功能

package main

import (
    "a"
    "b"
    "sync"
)

func main() {

    var wg sync.WaitGroup

    go b.Signal()

    wg.Add(1) // for simplicity; actual code start multiple goroutines of Work
    go a.Work(&wg)

    // wait until work is done
    wg.Wait()
    fmt.Println("Done.")
}

当我终止正在运行的进程时,我看到来自Quit的打印消息。 我预计一旦频道关闭,goroutines将在某个时刻select QuitChan案例并返回。

但他们继续跑步; 他们继续处理WorkChan中的项目。 好像被忽略了。 我在这里错过了什么? 频道是否关闭? 怎么还是开着?

首先,我认为你应该做一个简单的测试,并将其过去。 让其他人了解你的问题会更有帮助。

我改变了你的代码,让它像一个go代码,而不是其他语言。 现在它奏效了

在您的代码中,存在一些错误,我将其标记为ERROR注释。 有些是语法错误,比如创建WorkChan 有些是类型错误。

一个导入设计件事你应该知道,当你想退出后执行Stop()你应该关闭WorkChan在那里你将数据发送到WorkChan的insteal只返回在您收到的日期。

  •  package a import ( "fmt" "sync" ) // ERROR: can not do make in global var WorkChan chan int var QuitChan chan struct{} // Create chan when init func init() { fmt.Println("Init a") WorkChan = make(chan int) QuitChan = make(chan struct{}) } func Stop() { fmt.Println("Stop called, closing quit channel") close(QuitChan) } // Close the work channel where you send date func Start(wg *sync.WaitGroup) { i := 0 for { select { case <-QuitChan: fmt.Println("Closing work chan") close(WorkChan) wg.Done() return default: WorkChan <- i i++ } } } // Work will exit when workchan closed func Work(wg *sync.WaitGroup) { for item := range WorkChan { fmt.Printf("Receive %d\\n", item) } wg.Done() fmt.Println("Work exit") } 
  • b.go

     package b import ( "github.com/shitaibin/awesome/a" "os" "os/signal" "syscall" ) func Signal() { sChan := make(chan os.Signal, 1) signal.Notify(sChan, syscall.SIGTERM, syscall.SIGINT) // ERROR for { s := <-sChan switch s { case os.Interrupt, syscall.SIGTERM: a.Stop() return // should return free resource } } } 
  • main.go

     package main import ( "fmt" "github.com/shitaibin/awesome/a" "github.com/shitaibin/awesome/b" "sync" ) func main() { var wg sync.WaitGroup go b.Signal() wg.Add(1) // for simplicity; actual code start multiple goroutines of Work go a.Work(&wg) // ERROR: pointer wg.Add(1) go a.Start(&wg) // Send data and close channel when stop // wait until work is done wg.Wait() fmt.Println("Done.") } 
  • 结果

     // omit Receive 87028 Receive 87029 Receive 87030 Receive 87031 Receive 87032 Receiv^C101 <---- send signal here Receive 87102 Receive 87103 Receive 87104 Receive 87105 Receive 87106 Receive 87107 Receive 87108 Receive 87109 Receive 87110 Stop called, closing quit channel Receive 87111 Receive 87112 Closing work chan Work exit Done. 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM