«Go»: количество го-программ
«Го-программы» (goroutines) — это термин языка «Go», это функции, которые выполняются параллельно, что-то вроде местных потоков. Я пока ещё почти не умею с ними работать, только учусь. Одна из особенностей, на которую я сразу наткнулся, то что в языке есть специальный вызов «GOMAXPROCS» (модуль runtime), который указывает сколько процессоров будет задействованно, чтобы запускать го-программы.
По-умолчанию, «Go» использует только один процессор, вот цитата:
It should be smarter and one day it will be smarter, but until it is if you want CPU parallelism you must tell the run-time how many goroutines you want executing code simultaneously. There are two related ways to do this. Either run your job with environment variable GOMAXPROCS set to the number of cores to use (default 1); or import the runtime package and call runtime.GOMAXPROCS(NCPU).
В документации есть множество мест, где говорится, что сейчас планировщик го-программ работает очень плохо, его будут улучшать и однажды «GOMAXPROCS» уйдёт в историю; а пока приходится выставлять это значение вручную.
Возможно я ошибаюсь, но мне кажется очевидным, что значение этой директивы должно быть уж никак не меньше числа процессоров. Чтобы автоматически определять количество процессоров и указывать верное, по моему мнению, значение, я написал следующий код. Возможно ещё кому-нибудь пригодится.
package main
import ("syscall"; "runtime")
func main() {
if n, _ := syscall.SysctlUint32("hw.ncpu"); n > 0 {
runtime.GOMAXPROCS(int(n))
}
}
Может быть авторы языка решили, что основная аудитория будет использовать один поток и все. А те кому нужна многопоточность то они выставят нужное количество потоков вручную. Кстати, расчет количества процессоров идет на уровне компиляции или исполнения? В документаци на функцию есть где-нибудь указание на этот факт? А то скомпилируешь на 4 процессорном, а выполнишь на 2 и будет прога подглючивать.
Комментарий для orcinus.ru:
На уровне выполнения, это простой вызов sysctl, такой же как использует одноимённая утилита ( http://ru.wikipedia.org/wiki/Sysctl ). Этот вызов умеет очень многое рассказывать о системе, в том числе и про процессоры.
Кстати, этот код, конечно, не платформонезависим, под Windows вызова sysctl не существует, насколько я знаю.
Комментарий для orcinus.ru:
с чего бы?
Комментарий для orcinus.ru:
Программа, конечно, не будет подглючивать, просто выполняться будет медленнее, чем могла бы.
Кстати, под Windows можно проверить значение переменной окружения NUMBER_OF_PROCESSORS. Она точно есть со времён XP, возможно она была и раньше.
Комментарий для Евгения Степанищева:
Это число с учетом гипертрединга, скажем на i5 2 ядра, а NUMBER_OF_PROCESSORS равен 4. Выполнение приложение в 4 потока в таком случае будет не быстрее, чем в два. Впрочем, едва ли заметно хуже.
Комментарий для mixa.livejournal.com:
странно, Fritz Chess Benchmark показывает прирост производительности в 1.44 раза. и это у меня ещё относительно древний проц. а вы чем измеряли?
Комментарий для zg.livejournal.com:
Да накидал простой тест на яве, который делает много простых арифметических операций. При увеличении количества потоков с одного до двух производительность выросла почти ровно в 2 раза, до 4-х или более -- осталась практически такая же, как с двумя.
На более сложных тестах, возможно, и правда будет прирост, не зря же этот гипертридинг вообще придумали.
А что со сборкой мусора? И как происходит диспетчеризация потоков? В erlang/otp задавается число планировщиков процессов(насколько я понял, GOMAXPROCS тоже про это), исполняющих параллельно процессы vm и соответсвенно каждый планировщик может запускать gc для своих процессов, причем у каждого процесса vm своя куча. Интересно, как дела обстоят в Go.
Спасибо.
s/задавается/задается/g
s/соответсвенно/соответственно/g
Комментарий для anonymouse:
Go сам убирает мусор, но не имеет деструкторов, к примеру, о закрытии файлов надо заботиться самостоятельно, хотя для этого есть удобные средства.
Плохо происходит, если честно. Я завершу эксперименты, ещё расскажу об этом.
В Go не процессы и даже не потоки, там го-программы, правда на уровне системы эти го-процессы могут быть и потоками, но не обязательно, но это не процессы, в спецификации есть упоминание, что го-программы выполняются в одном адресном пространстве.
Евгений, я, наверное, не смог донести мысль и очень плохо задал вопрос.
Ужасно. Т. е. ’let it crash’ метод в go не работает? И падение го-программы ведет к падению всего рантайма/утечкам памяти?
Извините, но я не понял. Поправьте, пожалуйста:
1) Раз го-программы выполняются параллельно в одном адресном пространстве => их || исполняют потоки ОС в рамках рантайма Go.
2) Максимальное число этих потоков мы задаем, тогда как-то и как-то в рантайме должен производить планирование го-программ и раскидывание их по потокам рантайма.
3) Раз адресное пространство шареное, то очевидны проблемы блокированием всего рантайма GC на время сборки.
Я просто пытаюсь сравнить с erlang, о внутренностях которого имею некоторое представление, и понять, что же такого есть в Go, чего нет в erlang, который изобрели 20 лет назад.
Комментарий для anonymouse:
Падение го-программы ведёт к вызову panic, вызов panic можно перехватить. По поводу утечек памяти пока ничего сказать не могу, литературы по этому поводу нет, а я пока не исследовал.
Не обязательно. http://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0
У Go есть плохенький планировщик.
Увы, пока ничего не могу сказать по этому поводу.
Не знаю, я Erlang не знаю, но в Go куда более привычный синтаксис.
Комментарий для mixa.livejournal.com:
Возможно, Ява не умеет распределять операции так, чтобы они могли хорошо выполняться на HT, там есть особенности. Кроме того, HT реализован так, что некоторые программы могут даже замедлиться.
Комментарий для Евгения Степанищева:
Спасибо, за ответы!
Это понятно и известно, но мы же говорили про «CPU parallelism» и я к сожалению не знаю, как сопрограммы «прикручиваются» к SMP, если подкините ссылок --- буду признателен!
В целом, ясно, что ничего не ясно :) Успехов в дальнейших исследованиях!
Комментарий для anonymouse:
Если на что-то наткнусь, то кину обязательно!
Примечание: сейчас для определения количества процессоров нужно использовать вызов runtime.NumCPU ( http://golang.org/pkg/runtime/#NumCPU ).
Привет из 2016
Привет из 2020-го))
Привет из 2023-го))
☺☺☺