Подтвердить что ты не робот

Как моя программа Go может поддерживать все ядра процессора?

Goroutines - это легкие процессы, которые автоматически распределяются по времени на один или несколько потоков операционной системы по времени выполнения Go. (Это действительно классная функция Go!)

Предположим, что у меня есть параллельное приложение, такое как веб-сервер. В моей гипотетической программе много чего происходит, без большого количества несогласованных (Amdahl Law).

Похоже, что количество используемых в настоящее время потоков операционной системы по умолчанию равно 1. Означает ли это, что используется только один ядро ​​ЦП?

Если я запустил свою программу с помощью

runtime.GOMAXPROCS(runtime.NumCPU())

обеспечит разумное использование всех ядер на моем ПК?

Есть ли какая-либо "параллельная слабинка" из-за использования еще более используемых потоков ОС, например. через некоторые эвристические

runtime.GOMAXPROCS(runtime.NumCPU() * 2)

?

4b9b3361

Ответ 1

Из FAQ Go Go:

Почему моя мульти-горутинская программа не использует несколько процессоров?

Вы должны установить переменную среды оболочки GOMAXPROCS или использовать аналогично названную функцию пакета времени выполнения, чтобы позволить службе времени выполнения использовать более одного потока ОС.

Программы, выполняющие параллельные вычисления, должны быть полезны при увеличении GOMAXPROCS. Однако имейте в виду, что concurrency не parallelism.

(UPDATE 8/28/2015: Go 1.5 настроен на то, чтобы значение GOMAXPROCS по умолчанию было таким же, как и количество процессоров на вашем компьютере, поэтому это больше не должно быть проблемой)

и

Почему использование GOMAXPROCS > 1 иногда замедляет мою программу?

Это зависит от характера вашей программы. Проблемы, которые по сути являются последовательными, не могут быть ускорены добавлением большего количества горутов. concurrency становится parallelism, когда проблема внутренне параллельна.

В практическом плане программы, которые тратят больше времени на общение по каналам, чем на вычисления, будут испытывать ухудшение производительности при использовании нескольких потоков ОС. Это связано с тем, что отправка данных между потоками включает в себя контексты переключения, которые имеют значительную стоимость. Например, пример простого сита из спецификации Go не имеет значительного parallelism, хотя он запускает множество goroutines; увеличение GOMAXPROCS, скорее всего, замедлит его, чем ускорит его.

Go goroutine scheduler не так хорош, как должен быть. В будущем он должен распознавать такие случаи и оптимизировать использование потоков ОС. На данный момент GOMAXPROCS должен быть установлен для каждого приложения.

Короче: очень сложно заставить Go использовать "эффективное использование всех ваших ядер". Простое появление миллиарда goroutines и увеличение GOMAXPROCS так же сильно ухудшает вашу производительность, как ускоряет ее, потому что она будет постоянно переключать контексты потоков. Если у вас есть большая программа, которая является параллелизуемой, то увеличение GOMAXPROCS до количества параллельных компонентов отлично работает. Если у вас есть параллельная проблема, встроенная в практически непараллельную программу, она может ускориться, или вам может потребоваться творческое использование таких функций, как runtime.LockOSThread(), чтобы гарантировать, что среда выполнения распределяет все правильно (вообще говоря, Go просто тупо распространяется в настоящее время неблокирующие Goroutines беспорядочно и равномерно среди всех активных потоков).

Кроме того, GOMAXPROCS - это количество ядер ЦП, если оно больше, чем NumCPU. Я уверен, что он просто зажимает NumCPU. GOMAXPROCS не является строго равным числу потоков. Я не уверен на 100% точно, когда среда выполнения решает порождать новые потоки, но один экземпляр - это когда количество блокирующих goroutines, использующих runtime.LockOSThread() больше или равно GOMAXPROC, - это порождает больше потоков, чем ядра поэтому он может поддерживать простую работу программы.

В принципе, достаточно просто увеличить GOMAXPROCS и сделать использование всех ядер вашего процессора. Совсем другое дело на этом этапе разработки Go, чтобы на самом деле заставить его разумно и эффективно использовать все ядра вашего процессора, требуя, чтобы многие разработки и финализация программ стали правильными.

Ответ 2

На этот вопрос нельзя ответить, он слишком широк.

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

Никто не может ответить на вопрос типа "Есть ли эвристика, которая добавляет вдвое больше соли к моему обеду, будет ли она лучше?" так как это зависит от обеда (помидоры приносят гораздо больше от соли, чем клубника), ваш вкус и сколько соли уже есть. Попробуйте.

Далее: runtime.GOMAXPROCS(runtime.NumCPU()) достиг культового статуса, но контроль количества потоков путем установки переменной среды GOMAXPROCS извне может быть гораздо лучшим вариантом.

Ответ 3

runtime.GOMAXPROCS() задает количество (виртуальных) ядер процессора, которые ваша программа может использовать одновременно. Разрешить Перейти к использованию большего количества ядер процессора, чем вы на самом деле, не поможет, так как ваша система имеет только столько ядер процессора.

Чтобы работать в нескольких потоках, ваша программа должна иметь несколько goroutines, обычно вызовы функций с go someFunc(). Если ваша программа не запускает никаких дополнительных goroutines, она, естественно, будет работать только в одном потоке независимо от того, сколько процессоров/ядер вы можете использовать.

Отметьте это и следующие упражнения о том, как создавать goroutines.