Итак, у меня есть часть кода, которая является параллельной, и она предназначена для запуска на каждый процессор/ядро.Как определить, что предотвращает использование нескольких ядер в 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
?
Заранее спасибо
На самом деле у вас есть один скрытый мьютекс за каналом 'ch' – nvartolomei
Да, спасибо! Но мьютекс используется только «nw» раз, что обычно является низким числом по сравнению с обрабатываемыми данными, а канал используется очень поздно во всем процессе вычисления. Я не знаю, если это проблема, но даже если это так, мой вопрос остается: откуда я знаю, что из-за этого мьютекса мой код не использует больше процессоров? – AkiRoss
Вы правы. Я просто попробовал образец, похожий на ваш, и он использует все доступные ядра. Я думаю, что полный пример кода будет более полезен. – nvartolomei