Go语言使用channel等待任务结束

本文深入探讨了在Go语言中使用Channel等待Goroutine结束的两种方法,通过树的遍历实例展示Channel的应用,并讲解如何利用Select进行调度,包括定时器、Nil Channel和非阻塞读取Channel。此外,还介绍了传统同步机制如WaitGroup、Mutex和Cond的使用。

一、使用channel来等待goroutine结束

方法一:

type worker struct {
   in chan int
   done chan bool
}

func doneWorker(id int, w worker) {
   for n := range w.in {
      fmt.Printf("worker %d received %c\n", id, n)
      w.done <- true
   }
}

func createWorker(id int) worker{
   w := worker{
      in: make(chan int),
      done: make(chan bool),
   }

   go doneWorker(id, w)
   return w
}

func chanDemo() {
   var workers [10]worker

   for i, _ := range workers {
      workers[i] = createWorker(i)
   }

   for i, worker := range workers {
       worker.in <- 'a' + i
   }

   for _, worker := range workers{
      <- worker.done
   }

   for i, worker := range workers {
      worker.in <- 'A' + i
   }

   for _, worker := range workers{
      <- worker.done
   }
}

func main() {
   chanDemo()
}

方法二:

type worker struct {
   in chan int
   done func()
}

func doneWorker(id int, w worker) {
   for n := range w.in {
      fmt.Printf("worker %d received %c\n", id, n)
      w.done()
   }
}

func createWorker(id int, wg *sync.WaitGroup) worker{
   w := worker{
      in: make(chan int),
      done: func() {
         wg.Done()
      },
   }

   go doneWorker(id, w)
   return w
}

func chanDemo() {
   var wg sync.WaitGroup

   var workers [10]worker
   for i, _ := range workers {
      workers[i] = createWorker(i, &wg)
   }

   wg.Add(20)

   for i, worker := range workers {
       worker.in <- 'a' + i
   }

   for i, worker := range workers {
      worker.in <- 'A' + i
   }

   wg.Wait()
}

func main() {
   chanDemo()
}

二、使用Channel来实现树的遍历

func (node *Node) TraverseWithChannel() chan *Node{
   out := make(chan *Node)
   go func() {
      node.TraverseFunc(func(node *Node) {
         out <- node
      })
      close(out)
   }()

   return out
}

三、使用Select来进行调度

1.定时器的使用
2.select中使用Nil channel
3.select default(非阻塞式从channel中获取值)

func generator() chan int{
   out := make(chan int)
   go func() {
      i := 0
      for {
         time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond)
         out <- i
         i++
      }
   }()

   return out
}

func worker(id int, c chan int)  {
   for n := range c {
      time.Sleep(1 * time.Second)
      fmt.Printf("Worker %d received %d\n", id, n)
   }
}

func createWorker(id int) chan int{
   c := make(chan int)
   go worker(id, c)
   return c
}

func main() {
   var c1, c2 = generator(), generator() // c1 and c2 = nil
   w := createWorker(0)
   var values []int
   tm := time.After(10 * time.Second)
   tick := time.Tick(time.Second)
   for {
      var activeWorker chan int
      var activerValue int
      if len(values) > 0 {
         activeWorker = w
         activerValue = values[0]

      }
      select {
      case n := <-c1:
         values = append(values, n)
      case n := <-c2:
         values = append(values, n)
      case activeWorker <-activerValue:
         values = values[1:]
      case <-time.After(800 * time.Millisecond):
         fmt.Println("timeout")
      case <-tick:
         fmt.Println("queue len =", len(values))
      case <-tm:
         fmt.Println("Bye")
         return

      //default:
         //fmt.Println("No value received")
      }
   }
}

四、传统同步机制

1.WaitGroup
2.Mutex
3.Cond

type atomicInt struct {
   value int
   lock sync.Mutex
}

func (a *atomicInt)  increment(){
   fmt.Println("safe increment")
   func(){
      a.lock.Lock()
      defer a.lock.Unlock()
      a.value++
   }()
}

func (a *atomicInt) get() int {
   a.lock.Lock()
   defer a.lock.Unlock()

   return a.value
}
func main() {
   var a atomicInt
   a.increment()
   go func() {
      a.increment()
   }()
   time.Sleep(time.Millisecond)
   fmt.Println(a.get())
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值