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

Kir*_*ril 5 semaphore channel go goroutine

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

ints := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Run Code Online (Sandbox Code Playgroud)

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

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)
}
Run Code Online (Sandbox Code Playgroud)

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

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

Jim*_*imB 14

您不能以这种方式使用信号量(在这种情况下是通道).在处理值和派遣更多goroutine时,无法保证它不会为空.在这种情况下,这并不是特别关注,因为你是同步调度工作,但是因为没有无竞争方法来检查通道的长度,所以没有原语可以等待通道的长度达到0.

使用a 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()
Run Code Online (Sandbox Code Playgroud)


Jus*_*n S 5

使用“工作池”来处理您的数据。它比为每个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()
Run Code Online (Sandbox Code Playgroud)