• golang使用channel来同步goroutine


    在golang中同步goroutine有2种方法,要么使用channel,要么使用sync.WaitGroup,本文就是介绍如何通过channel来同步goroutine。先看代码。

     1 package main
     2 
     3 import (
     4     "os"
     5     "os/signal"
     6     "runtime"
     7     "log"
     8     "syscall"
     9 )
    10 
    11 const NUM_OF_QUIT int = 100
    12 
    13 func main() {
    14     runtime.GOMAXPROCS(runtime.NumCPU())
    15     done := make(chan bool)
    16     receive_channel := make(chan chan bool)
    17     finish := make(chan bool)
    18 
    19 
    20     for i := 0; i < NUM_OF_QUIT; i++ {
    21         go do_while_select(i, receive_channel, finish)
    22     }
    23 
    24     go handle_exit(done, receive_channel, finish)
    25 
    26     <-done
    27     os.Exit(0)
    28 
    29 }
    30 func handle_exit(done chan bool, receive_channel chan chan bool, finish chan bool) {
    31     sigs := make(chan os.Signal, 1)
    32     signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
    33     chan_slice := make([]chan bool, 0)
    34     for {
    35         select {
    36         case  <-sigs:
    37             for _, v := range chan_slice {
    38                 v <- true
    39             }
    40             for i := 0; i < len(chan_slice); i++ {
    41                 <-finish
    42             }
    43             done <- true
    44             runtime.Goexit()
    45         case single_chan := <-receive_channel:
    46             log.Println("the single_chan is ", single_chan)
    47             chan_slice = append(chan_slice, single_chan)
    48         }
    49     }
    50 }
    51 func do_while_select(num int, rece chan chan bool, done chan bool) {
    52     quit := make(chan bool)
    53     rece <- quit
    54     for {
    55         select {
    56         case <-quit:
    57             done <- true
    58             runtime.Goexit()
    59         default:
    60             //简单输出
    61             log.Println("the ", num, "is running")
    62         }
    63     }
    64 }

    上面的代码保存为example.go,通过gotool编译代码:

    go build example.go

    在当前目录下有example文件,在终端运行这个文件

    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    2013/03/19 21:17:14 the  0 is running
    ......

    上面不断输出goroutine中的数字,等待退出信号。

    新打开一个终端,通过ps找到这个进程名,通过kill工具干掉这个进程:

    $ps aux | grep example
    user  4026 77.9  0.0  39436  1716 pts/1    Sl+  21:19   0:17 ./example
    $kill 4026

    不久就可以看到在第一个终端里面不再打印,至此演示完毕。

    代码思想:

    新建NUM_OF_QUIT个goroutine,这些个goroutine里面新建1个chan bool,通过这个channel来接受退出的信号,这些channel在新建的时候,已经发给了handle_exit。在handle_exit这个goroutine里面,1方面监控由系统发过来的退出信号,然后再通知其他的goroutin优雅地退出;另一方面通过slice收集其他goroutine发过来的channel。handle_exit通知其他的goroutine优雅退出后,再发信号给main进程主动退出。

    可以修改NUM_OF_QUIT值,例如改为10000,这个时候,kill命令发出去后,要等待相当长的一段时间才能看到第一个终端停止打印。

    参考:

    Go by Example: Signals

    https://gobyexample.com/signals

     转贴请注明来自:格通

  • 相关阅读:
    Oracle错误——ORA-12704:字符集不匹配
    nodejs 错误问题解决
    windows 卸载 node.js 怎么卸载搜索
    Git安装配置及基本使用(windows)
    破解photoshop cs6 mac
    将text中的数字转换为字符串
    JavaScript 为什么不推荐使用 eval?
    Permission denied (publickey).
    linux 命令
    恢复 git reset -hard 的误操作
  • 原文地址:https://www.cnblogs.com/getong/p/2970045.html
Copyright © 2020-2023  润新知