Golang:限制阻塞操作的并发级别

Golang:限制阻塞操作的并发级别,go,Go,我有以下情况: 我在一个频道上收到一条信息,告诉我上传一个文件。上传是通过阻塞函数uploadToServer进行的。zipGen频道每秒可能会收到几条消息,我希望最多同时上传5个文件,不是更多,但可能更少-这取决于第三个工作者在zipGen上发送的消息数量,这超出了本问题的范围 listenToZips函数在go例程中运行,go listenToZips位于文件的init函数上: func listenToZips() { for { select {

我有以下情况: 我在一个频道上收到一条信息,告诉我上传一个文件。上传是通过阻塞函数uploadToServer进行的。zipGen频道每秒可能会收到几条消息,我希望最多同时上传5个文件,不是更多,但可能更少-这取决于第三个工作者在zipGen上发送的消息数量,这超出了本问题的范围

listenToZips函数在go例程中运行,go listenToZips位于文件的init函数上:

func listenToZips() {
    for {
        select {
        case zip := <-zipGen:
          uploadToServer(zip) // this is blocking
        }
    }
}
如果我启动go uploadToServerzip而不是uploadToServerzip,我会获得太多的并发性,例如,我的程序将尝试同时上载10个文件,但我希望最多上载5个

另一方面,没有像上面的函数那样使用uploadToServerzip,我一次只上传一个文件,因为uploadToServerzip被阻塞了

我如何实现这种级别的控制,以允许我同时最多上载5个文件


谢谢

最简单的选项是预加载goroutine,它以循环的方式从通道获取输入并上传。在每个goroutine的上下文中,操作将被阻塞,但是N个goroutine会这样做。当然,只有一个goroutine会收到每条消息

func listenToZips(concurrent int) {

    for i:=0; i < concurrent; i++ {

      // spawn a listener goroutine
      go func() {

         for {
            select {
            case zip := <-zipGen:
               uploadToServer(zip) // this is blocking
            }
         }
      }()

   }

}
当然,您可以添加停止条件,可能使用不同的频道,但基本思想是一样的。

尝试以下方法:


我喜欢简单。谢谢@orcaman当限制非常大时,我正在使用一个更复杂的模式,并且所需的并发性可能会改变,所以如果大多数goroutine是空闲的,我不想运行恒定数量的goroutine。但是在小范围内,这是最好的选择。顺便说一下,如果select中只有一个case,不包括默认case,那么整个循环几乎与简化的:for-zip:=range-zipGen{uploadtoserver-zip}完全相同。一个不同之处是简化版更好地处理通道关闭;如果频道关闭,您的代码将忙于循环调用uploadToServernil,并尽可能快地进行调用。@DaveC感谢您发现这一点
 limiter := NewConcurrencyLimiter(10)
 limiter.Execute(func() {
        uploadToServer()
 })
 limiter.Wait()