Поиск в WeChat【Жареная рыба с мозгами] Обратите внимание на эту жареную рыбу с печенью. эта статьяGitHub GitHub.com/Vicious Genetics/Нет...В комплекте с моей серией статей, материалов и книг по Go с открытым исходным кодом.
Всем привет, я жареная рыба.
Золото три серебра четыре в последнее время, это сезон интервью. В моей группе по общению с читателями Go есть много мелких партнеров, которые обсуждают некоторые вопросы интервью Go, с которыми они столкнулись во время своих интервью.
Сегодняшний главный герой — это дополнительный вопрос (вопрос) универсального вопроса модели GMP интервью Го, то есть «Модель GMP, почему P? "
Фактически, за дальнейшим изучением вопроса суть этого вопроса интервью состоит в том, чтобы спросить: "Для модели GMP, почему G и M не связаны напрямую, и нужно добавить еще один P?Так хлопотно, для чего это нужно, и какую проблему он должен решить?? "
В этой статье Fried Fish расскажет вам о причинах изменений в моделях GM и GMP.
модель ГМ
Перед GO1.1 Go Prining Model на самом деле является моделью GM, то есть нет P.
Сегодня мы оглядываемся назад вместе с дизайном.
Расшифровать исходный код Go1.0
Один из способов понять что-то — посмотреть на исходный код и посмотреть на Go1.0.1 вместе с жареной рыбой.Исходный код планировщикаОсновные ключевые этапы:
static void
schedule(G *gp)
{
...
schedlock();
if(gp != nil) {
...
switch(gp->status){
case Grunnable:
case Gdead:
// Shouldn't have been running!
runtime·throw("bad gp->status in sched");
case Grunning:
gp->status = Grunnable;
gput(gp);
break;
}
gp = nextgandunlock();
gp->readyonstop = 0;
gp->status = Grunning;
m->curg = gp;
gp->m = m;
...
runtime·gogo(&gp->sched, 0);
}
- передача
schedlock
Методы для получения глобальных замков. - После успешного получения глобальной блокировки измените текущее состояние Goroutine с состояния Running (запланировано) на состояние Runnable (может быть запланировано).
- передача
gput
метод сохранения информации, такой как текущий статус текущей Goroutine, для последующего использования; - передача
nextgandunlock
метод, чтобы найти следующую горутину, которую можно запустить, и снять глобальную блокировку для использования другими планировщиками. - После запуска следующей горутины измените ее статус выполнения на «Выполняется».
- передача
runtime·gogo
только что полученный метод для запуска следующей Goroutine.
Думая о модели GM
Анализируя исходный код планировщика Go1.0.1, мы можем найти более интересный момент. То есть сам планировщик (метод расписания), в обычном процессе он не вернется, то есть не завершит основной процесс.
Он продолжит выполнение процесса планирования. После того, как GoroutineA будет завершена, он начнет искать GoroutineB. Когда он найдет B, он передаст завершенные права планирования A B и позволит начать планирование GoroutineB, то есть бежать.
Конечно, есть и G, который блокируется. Если предположить, что G выполняет некоторые системные и сетевые вызовы, это приведет к остановке G. В это время M (системный поток) будет помещен обратно в очередь ядра, ожидая нового раунда пробуждения.
Недостатки модели GM
Таким образом, поверхность выглядит, модели GM кажутся небьющими, нет дефекта. Но зачем менять это?
В 2012 году Дмитрий Вьюков опубликовал статью «Scalable Go Scheduler Design Doc», по-прежнему является основным объектом крупных исследовательских статей о планировщике Go. В статье описываются общие причины и соображения. Следующее содержание будет относиться к этой статье.
Текущий (со ссылкой на модель GM Go1.0) планировщик Goroutine ограничивает масштабируемость параллельных программ, написанных на Go, особенно серверов с высокой пропускной способностью и программ параллельных вычислений.
Реализация имеет следующие проблемы:
- Есть один глобальный мьютекс (Sched.Lock) и централизованное управление состоянием:
- Мьютекс должен защищать все операции, связанные с горутинами (создание, завершение, изменение расписания и т. д.), что приводит к серьезной конкуренции за блокировку.
- Проблемы, пройденные Goroutine:
- передача горутины (G) (G.nextg): рабочие потоки (M) часто передают исполняемые горутины.
- Вышеупомянутое может привести к увеличению задержки и дополнительным накладным расходам. Каждый M должен иметь возможность запускать любой исполняемый G, особенно тот M, который только что создал G.
- Каждый M должен делать кеш памяти (M.mcache):
- Это приведет к чрезмерному потреблению ресурсов (каждый mcache может поглощать 2M кеша памяти и других кешей) и плохой локализации данных.
- Частая блокировка/разблокировка потока:
- Потоки часто блокируются и разблокируются при наличии системных вызовов. Это добавляет много дополнительных накладных расходов на производительность.
Модель GMP
Для решения вышеуказанных проблем модели GM в Go1.1 Дмитрий Вьюков добавил компонент P (Processor) на основе модели GM. И внедрить алгоритм Work Stealing для решения некоторых новых проблем.
Модель GMP, в предыдущей статье «Друзья группы Go спрашивают: Насколько уместно количество горутин, повлияет ли это на сборку мусора и планирование? уже было объяснено в.
Друзья, которые считают, что это хорошо, могут обратить на это внимание, и я не буду повторяться здесь.
какие изменения
Какие изменения произойдут при добавлении P? Давайте говорить более откровенно.
-
Каждый P имеет свою собственную локальную очередь, что значительно снижает прямую зависимость от глобальной очереди, а эффект заключается в снижении конкуренции за блокировку. Самая большая потеря производительности модели GM — это конкуренция замков.
-
Каждый P на относительном балансе, в модели также реализован алгоритм GMP Work Stealing, если P - локальная очередь пуста, G может украсть из локальной очереди запуска или глобальной очереди для запуска другого из P, уменьшить простои, улучшить ресурс использование.
Почему П
В это время некоторые друзья будут озадачены.Если вы хотите реализовать локальную очередь и алгоритм Work Stealing, почему бы не добавить их непосредственно в M, M также может реализовать аналогичные компоненты. Зачем добавлять еще один компонент P?
В сочетании с позиционированием M (системный поток), если вы это сделаете, возникают следующие проблемы:
-
Вообще говоря, число M будет больше, чем P. Как и в Go, число M по умолчанию равно 10000, а число P по умолчанию — это количество ядер ЦП. Кроме того, из-за свойств М, то есть при наличии системного блокирующего вызова, который блокирует М и недостаточно, М будет продолжать увеличиваться.
-
Если M продолжает увеличиваться, если локальная очередь монтируется на M, значит, соответственно будет увеличиваться и локальная очередь. Это явно неразумно, потому что управление локальной очередью усложнится, а производительность Work Stealing сильно снизится.
-
После того, как M заблокирован системным вызовом, мы ожидаем, что его невыполненные задачи будут назначены другим для продолжения работы, вместо того, чтобы заставлять все останавливаться, как только он блокируется.
Поэтому неразумно использовать M, тогда введение нового компонента P и ассоциирование локальной очереди с P может очень хорошо решить эту проблему.
Суммировать
Сегодняшняя статья объединяет некоторую историю, анализ причин и описания решений для всего планировщика языка Go.
Вопрос «модель GMP, почему должна быть буква P» похож на понимание дизайна системы, потому что многие люди сейчас повторяют модель GMP или проходят ее с лапшой быстрого приготовления, чтобы справиться с интервью. И нам нужно научиться понимать настоящую причину этого.
Знание того, что это такое, и знание того, почему это происходит, может сломать игру.
Если у вас есть какие-либо вопросы, пожалуйста, оставьте отзыв и обменяйтесь мнениями в области комментариев.Лучшие отношения - это достигать друг друга, твойподобното естьжареная рыбаСамая большая мотивация для творчества, спасибо за поддержку.
Статья постоянно обновляется, вы можете выполнить поиск [рыба, жареная в мозгу] на WeChat, чтобы прочитать, ответить [000] Я собираюсь провести собеседование с производителями первого уровня по алгоритмам и данным для решения проблемы; эта статьяGitHub GitHub.com/Vicious Genetics/Нет...Он был включен, добро пожаловать в Star, чтобы призвать больше.