簡體   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