2017-02-21 34 views
1

Итак, у меня есть часть кода, которая является параллельной, и она предназначена для запуска на каждый процессор/ядро.Как определить, что предотвращает использование нескольких ядер в golang?

Есть два больших входных векторов с выходными значениями

var (
    input = make([]float64, rowCount) 
    output = make([]float64, rowCount) 
) 

они заполнены/и хочу вычислить расстояние (ошибка) между каждым ввода-вывода пары. Будучи пары независимы, возможная версия одновременно является следующее:

var d float64 // Error to be computed 
// Setup a worker "for each CPU" 
ch := make(chan float64) 
nw := runtime.NumCPU() 
for w := 0; w < nw; w++ { 
    go func(id int) { 
     var wd float64 
     // eg nw = 4 
     // worker0, i = 0, 4, 8, 12... 
     // worker1, i = 1, 5, 9, 13... 
     // worker2, i = 2, 6, 10, 14... 
     // worker3, i = 3, 7, 11, 15... 
     for i := id; i < rowCount; i += nw { 
      res := compute(input[i]) 
      wd += distance(res, output[i]) 
     } 
     ch <- wd 
    }(w) 
} 
// Compute total distance 
for w := 0; w < nw; w++ { 
    d += <-ch 
} 

Идея заключается в том, чтобы иметь один рабочий для каждого процессора/ядра, и каждый работник обрабатывает подмножество строк.

Проблема, с которой я столкнулся, заключается в том, что этот код не быстрее, чем серийный код.

Теперь я использую Go 1.7, поэтому runtime.GOMAXPROCS должен быть уже установлен на runtime.NumCPU(), но даже при его установке явно не улучшается производительность.

  • расстояние всего (a-b)*(a-b);
  • вычисление немного сложнее, но должно быть реентерабельным и использовать глобальные данные только для чтения (и использует функции math.Pow и math.Sqrt);
  • не работает другой горутин.

Таким образом, помимо доступа к глобальным данным (вход/выход) для чтения, нет никаких блокировок/мьютексы, что Я ознакомлен (не используя math/rand, например).

Я также скомпилировал -race и ничего не появилось.

У моего хоста 4 виртуальных ядра, но когда я запускаю этот код, я получаю (используя htop) использование процессора до 102%, но я ожидал чего-то около 380%, как это было в прошлом с другим кодом go, который использовал все ядра.

Я хотел бы исследовать, но я не знаю, как среда выполнения распределяет потоки и назначает goroutines.

Как я могу отладить такие проблемы? Может ли pprof помочь мне в этом случае? Как насчет пакета runtime?

Заранее спасибо

+1

На самом деле у вас есть один скрытый мьютекс за каналом 'ch' – nvartolomei

+0

Да, спасибо! Но мьютекс используется только «nw» раз, что обычно является низким числом по сравнению с обрабатываемыми данными, а канал используется очень поздно во всем процессе вычисления. Я не знаю, если это проблема, но даже если это так, мой вопрос остается: откуда я знаю, что из-за этого мьютекса мой код не использует больше процессоров? – AkiRoss

+0

Вы правы. Я просто попробовал образец, похожий на ваш, и он использует все доступные ядра. Я думаю, что полный пример кода будет более полезен. – nvartolomei

ответ

1

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

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

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

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