如何等到缓冲通道(信号量)为空?

时间:2016-09-29 17:25:07

标签: go semaphore channel goroutine

我有一个整数片,它们被同时操作:

ints := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

我使用缓冲通道作为信号量,以便具有同时运行的例程的上限:

sem := make(chan struct{}, 2)

for _, i := range ints {
  // acquire semaphore
  sem <- struct{}{}

  // start long running go routine
  go func(id int, sem chan struct{}) {
    // do something

    // release semaphore
    <- sem
  }(i, sem)
}

上面的代码可以很好地工作,直到达到最后或最后两个整数,因为程序在最后一个例程完成之前结束。

问题:如何等待缓冲通道耗尽?

5 个答案:

答案 0 :(得分:11)

您不能以这种方式使用信号量(在这种情况下为频道)。当你处理价值并派遣更多的goroutines时,不能保证它在任何时候都不会是空的。在这种情况下,这并不是特别关注,因为您同步调度工作,但因为没有无种族方式来检查频道的长度,所以没有原语等待频道的长度达到0。

使用sync.WaitGroup等待所有goroutine完成

sem := make(chan struct{}, 2)

var wg sync.WaitGroup

for _, i := range ints {
    wg.Add(1)
    // acquire semaphore
    sem <- struct{}{}
    // start long running go routine
    go func(id int) {
        defer wg.Done()
        // do something
        // release semaphore
        <-sem
    }(i)
}

wg.Wait()

答案 1 :(得分:1)

使用“工作人员池”处理您的数据。比每个 int运行goroutine更为干净,为其中的变量分配内存等等......

ints := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

ch := make(chan int)

var wg sync.WaitGroup

// run worker pool
for i := 2; i > 0; i-- {
    wg.Add(1)

    go func() {
        defer wg.Done()

        for id := range ch {
            // do something
            fmt.Println(id)
        }
    }()
}

// send ints to workers
for _, i := range ints {
    ch <- i
}

close(ch)

wg.Wait()

答案 2 :(得分:0)

显然,没有人在等待你的例程完成。因此,程序在最后2个例程完成之前结束。在程序结束之前,您可以使用工作组等待所有的例行程序完成。这告诉它更好 - https://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/

答案 3 :(得分:0)

您可以在for循环中使用当前goroutine等待“子goroutines”

semLimit := 2
sem := make(chan struct{}, semLimit)

for _, i := range ints {
  // acquire semaphore
  sem <- struct{}{}

  // start long running go routine
  go func(id int, sem chan struct{}) {
    // do something

    // release semaphore
    <- sem
  }(i, sem)
}

// wait semaphore
for i := 0; i < semLimit; i++ { 
  wg<-struct{}{} 
}

可选地,也可以用import sync的经济性来编写一个简约的“信号量等待组”

semLimit := 2
// mini semaphored waitgroup 
wg := make(chan struct{}, semLimit)
// mini methods
wgAdd := func(){ wg<-struct{}{} }
wgDone := func(){ <-wg }
wgWait := func(){ for i := 0; i < semLimit; i++ { wgAdd() } }

for _, i := range ints {
  // acquire semaphore
  wgAdd()

  // start long running go routine
  go func(id int, sem chan struct{}) {
    // do something

    // release semaphore
    wgDone()
  }(i, sem)
}

// wait semaphore
wgWait()

答案 4 :(得分:-1)

这是一个工作示例。最后的 app/packs/entrypoints/application.js 循环强制程序等待 直到工作完成:

<%= stylesheet_pack_tag "application" %>