2015-08-26 2 views
4

Предположим, у меня есть доступный для чтения запрос на задание, он может или не может выполнять задачу (зависит от рабочей нагрузки) Конкретно так, что не может быть никакой работы в течение нескольких часов и то может возникнуть внезапная ошибка в задачахЛучший способ управления динамическим пулом goroutine

Я хочу, чтобы мой бассейн goroutine увеличивался с 1 на N, где N является максимальным параллелизмом при появлении работы, а затем автоматически сворачивается до 1, где не было работы для goroutine для дольше, чем X секунд, чтобы избежать потери памяти/процессора.

Я мог бы использовать только фиксированный пул, так как goroutines дешево дешевы, но мне не нравится идея о том, что у вас будут тысячи гонок в режиме ожидания. У меня может быть больше пользы для этих ресурсов (должно быть, в основном, тарана, но все же)

Сворачивание часть довольно легко

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 (максимальный параллелизм) goroutines, с возможностью в конечном итоге свести к более разумным числам (1 в минуту) при уменьшении рабочей нагрузки

P.S. Я видел пакет https://github.com/Jeffail/tunny, но похоже, что он не имеет ничего похожего на адаптивное масштабирование текущего размера пула. Я что-то упускаю?

Спасибо!

+5

Очень редко используется пул goroutines, так как управление ими обычно больше накладных расходов, чем отправка их при необходимости. – JimB

+1

Кроме того, если вы не знаете, стек для одного goroutine имеет только 2k, и это пространство стека не (в настоящее время) не исправлено, а сохраняется для будущих goroutines. Если пул упрощает решение, его динамическое изменение не сэкономит вам, если угодно. – JimB

+0

Дело в том, что у меня несколько очередей задач, и один процесс переходит к задачам из этих очередей. Если какая-то очередь исчерпана, но в конечном итоге работает, чтобы разрешить 1000 параллелизма (1000 одновременно запущенных goroutines), у меня сейчас 1000 бесплатных хостов, но я мог бы использовать их в обработке вещей из другой очереди ... Хотя, вероятно, я копаю глубокие и over-optimizing – let4be

ответ

1

Ну, я не уверен, что пул - это то, что вам нужно. Goroutines быстро запускаются, и вам, вероятно, не нужно постоянно их готовить.

Для этой задачи я бы использовал простой семафор. Очень легко реализовать семафор в Go, используя каналы. Вы можете увидеть мой личный пример here.

Вы просто создать семафор с требуемой мощностью (который будет вашим максимальное число разрешенных goroutines), а затем:

  1. Acqiure семафора на goroutine начать
  2. Отпустить его на goroutine конце

Простой как это. И не беспокойтесь о необходимости запускать их по требованию; это действительно чрезмерная оптимизация.

Смежные вопросы