管理动态goroutine池的最佳方法

时间:2015-08-26 13:21:48

标签: go pool goroutine

我们说我有一个任务提供者 - 可读渠道,它可能会也可能不会提供任务(取决于工作量) 具体是因为几个小时可能没有工作,然后任务可能突然出现

我想让我的goroutine池从1增长到N,其中N是工作出现时的最大并发数,然后自动折叠到1,其中goroutine的工作时间超过X秒以避免内存/ cpu浪费

我本来可以只使用一个固定的游泳池,因为goroutines很便宜,但我不想拥有成千上万的闲置goroutines我可能更好地利用这些资源(应该主要是ram但仍然)

折叠部分非常简单

for {
    timeoutTimer := time.NewTimer(WORKER_ROUTINE_TIMEOUT)

    select {
    case taskContext, isBatchRunning := <-runner.tasksCh:
        if !isBatchRunning {
            log.Print("task provider is closed, quit worker goroutine")
            return
        }

        runner.job.Process(&taskContext)
    case <-timeoutTimer.C:
        return
    }
}

但我不确定如何让游泳池动态增长,即哪种情况会产生一个新的

此池的优先级是能够在增加的负载下快速做出反应并扩展到N(最大并发)goroutine,当工作负载减少时能够最终崩溃到更合理的数字(1分钟)

P.S。我看到了一个https://github.com/Jeffail/tunny包,但看起来它没有类似于当前池大小的自适应缩放。我错过了什么吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

嗯,我不确定你需要一个游泳池。 Goroutines很快就会推出,你可能不需要一直保持它们的准备状态。

对于这个任务,我会使用一个简单的信号量。使用频道在Go中实现信号量非常容易。您可以看到我的个人示例here

您只需创建一个具有所需容量的信号量(这将是您允许的最大goroutines数量)然后:

  1. 在goroutine开始时获取信号量
  2. 在goroutine end上发布
  3. 这很简单。 并且不用担心需要按需启动它们;它真的过度优化了。