Каков идеальный размер буферизованного канала и количество рабочих? - PullRequest
0 голосов
/ 09 мая 2018

Я пытаюсь построить асинхронный кодек. Я реализовал диспетчер заданий, который имеет доступ к буферизованному каналу заданий

var JobChannel chan Job = make(chan Job, 100000)

диспетчер принимает в качестве входных данных количество работников и назначает им работу

func StartDispacher(numberOfWorkers int){
    // start workers
    wg := &sync.WaitGroup{}
    wg.Add(numberOfWorkers)
    for i := int(1); i <= numberOfWorkers; i++ {
        go func(i int) {
            defer wg.Done()
            for j := range JobChannel {
                doWork(i, j)
            }
        }(i)
    }
}

моя основная функция запускает диспетчер и продолжает отдавать ему задания (в данном случае 200000 заданий)

workDispatcher.StartDispacher(2*runtime.NumCPU())
for i := 0; i < 200000; i++ {
    j := workDispatcher.Job{
        BytePacket: d,
        JobType:    workDispatcher.DECODE_JOB,
    }
    workDispatcher.JobChannel <- j
}

после экспериментов: оказывается, есть 2 фактора, которые влияют на производительность этого кода

  • размер буферизованного канала JobChannel
  • количество рабочих func StartDispacher(numberOfWorkers int)

Существует ли стандартный способ найти оптимальные значения для этих параметров и возможно ли сделать эти значения независимыми от физической настройки машины, на которой выполняется код?

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

Вам всегда нужно измерять, чтобы определить, как система будет работать под нагрузкой. Хорошая новость заключается в том, что у вас есть только 2 переменные, которые в основном независимы, поэтому об этом довольно легко рассуждать.

Количество работников определяет ваш параллелизм, поэтому сравните результаты обработки, чтобы увидеть, каков оптимальный параллелизм. Обычно существует ряд параллельных процессов, выше которых доходность резко падает.

Размер канала такой же, как и любой другой «буфер» в системе. Больший буфер может обрабатывать большие пики на входе за счет возможного увеличения задержки и использования памяти.

0 голосов
/ 10 мая 2018

На практике я нахожу, что есть три размера буфера, которые имеют значение: 0, 1 и «верхняя граница общего количества отправлений».

0 дает синхронное поведение.

1 дает асинхронное поведение: это полезно в операторе select с регистром default.

Верхняя граница общего количества отправлений обеспечивает гарантированное неблокирующее поведение: вы можете отправлять на него без select, не рискуя утечкой горутина.

Другие числа могут обеспечить немного лучшую пропускную способность, но в масштабе они все равно будут бороться в строке кэша, содержащей внутренний мьютекс канала, и они с большей вероятностью замаскируют потенциальные взаимоблокировки и утечки кода.

0 голосов
/ 09 мая 2018

Ответ - нет. Оптимальная настройка будет зависеть не только от программного обеспечения, которое вы запускаете в doWork (от того, насколько интенсивным будет ЦП и IO, зависит эта функция), но также от того, сколько инструкций может выполнять ваше оборудование и с каким IO может работать ваша система.

Это означает, что это может зависеть от того, какой SSD установлен или не установлен в вашей системе, или даже от пропускной способности вашей системы, если ваша система выполняет действия, связанные с доступом в Интернет, сколько физических ядер имеет ваш ЦП и т.д. ...

...