Автор: Линь Гуаньхун / Призраки под рукой
Самородки:Наггетс Талант /user/178526…
Гитхаб:GitHub.com/afan913337456…
Облачная колонка Tencent:cloud.Tencent.com/developer/U…
пролог
Правильное понимание взаимосвязи между G, M и P может дать более глубокое понимание механизма планирования сопрограмм! В этой статье будет полностью представлен механизм планирования сопрограмм go, в том числе:
- Основные компоненты объекта календарного планирования
- Отношения и разделение труда между объектами
- Как выполняются горутины
- Управление системным потоком ядра горутины
- goroutine coroutine прерывание приостанавливает и возобновляет
- Как GOMAXPROCS влияет на производительность параллелизма
Кстати: моя техническая книга «Практика разработки блокчейн-приложений на Ethereum» опубликована и может быть приобретена в Интернете.
содержание
- Три основных объекта планировщика
- Взаимосвязь и характеристики G, M, P
- Связь между локальной G-очередью и глобальной G-очередью
- Горутина от постановки в очередь до исполнения
- Ответьте на вопросы ①
- восстановление после перерыва
- Настройка производительности GOMAXPROCS
Три основных объекта планировщика:
Golang называют Go, Go's协程(goroutine)
и наше общее线程(Thread)
Мол, есть свой планировщик.
- G (Горутина) означает сопрограмму, которая используется в каждом коде.
go 关键词
объект, который будет создан, когда - M (рабочая нить), рабочая нить
- P (процессор), представляющий
处理器
, он же контекст
Взаимосвязь и характеристики трех G-M-P:
- Каждый запущенный M должен быть привязан к P. После создания потока M он проверит и выполнит объект G (горутина).
- Каждый P содержит сопрограмму G
队列
- В дополнение к очереди G, которую содержит каждый P, планировщик также имеет глобальную очередь G.
- М от
队列中
Извлеките G и выполните - Число P
GOMAXPROCS
(максимум 256), фиксируется при запуске, в основном не модифицируется - Количество M не обязательно совпадает с количеством P (будут спящие M или P, не привязанные к M) (максимум 10000)
- P хранится в глобальном массиве (255) и поддерживает глобальный список свободных P
Связь между локальной очередью G и глобальной очередью G
- Глобальная очередь задач G будет обмениваться с каждой локальной очередью задач G в соответствии с определенной стратегией. Верно
协程任务
обмен - Порядок выполнения задачи G заключается в том, чтобы сначала найти ее в локальной очереди, а затем в локальной очереди, если она недоступна локально.
全局队列
Находить - перечислить
- Локальный и глобальный, глобальный номер G / номер P
- Местный и местный, передача половины за один раз
Горутина от постановки в очередь до исполнения
- Когда мы создаем объект G, это
gorutine
, он будет добавлен в локальную очередь или глобальную очередь - Если еще есть свободная P, создайте M, чтобы связать P, обратите внимание! Здесь P не должен был быть связан с M ранее, иначе условие бездействия не будет выполнено. Точки детализации:
- Сначала найдите свободный P, если нет, вернитесь напрямую
- Количество P не будет занимать больше, чем количество процессоров, установленное вами
- После того, как P свяжется с M, он инициализирует свою собственную очередь G, которая является
空队列
- Обратите внимание здесь
一个点
!- Независимо от того, в каком M G создается, пока P свободен, это приведет к созданию нового M
- Нет необходимости рассматривать, заполнена ли очередь G связанного P в текущем M
- Очередь инициализации P, привязанная к вновь созданному M, будет извлекать задачи из других очередей G.
- Это оставляет первый вопрос:
Если время выполнения задачи G слишком велико, она всегда будет занимать потоки M. Поскольку задачи G в очереди выполняются последовательно, другие задачи G будут заблокированы. Как избежать этой ситуации? --①
- М начнет
底层线程
,循环执行
G задач, которые можно найти. Вот G, который нужно искать в следующих аспектах:- найти в очереди P, к которой привязан текущий M
- Перейдите в очередь других P, чтобы найти
- Перейдите в глобальную очередь G, чтобы найти
- Порядок выполнения задачи G заключается в том, чтобы сначала найти ее в локальной очереди и найти в глобальной очереди, если локальной очереди нет.
- Когда программа запускается, сначала запускается основной поток, а затем основной поток связывает первый P
- Основная функция входа фактически выполняется как горутина.
Ответь на вопрос-①
Квант времени переключения сопрограммы составляет 10 мс, что означает, что горутина будет переключена на следующий G на M, когда она будет выполняться не более 10 мс. Этот процесс также называется中断,挂起
принцип:
Когда программа go запускается, она сначала создает специальный поток ядра.sysmon
, используемый для мониторинга и управления, а его внутренняя часть представляет собой цикл:
-
Запишите все задачи P's of G
计数 schedtick
, метка расписания будет увеличиваться после выполнения каждой задачи G -
Если отмечено
schedtick
Он не был увеличен, что указывает на то, что этот P выполнял ту же задачу G. Если он превышает 10 мс, добавьте тег tag в информацию о стеке этой задачи G. -
Затем, когда выполняется задача G, если она встречает не встроенный вызов функции, она один раз проверит флаг, затем прервет себя, добавит себя в конец очереди и выполнит следующий вызов G.
-
если не встретится
非内联函数
Если она вызывается (иногда обычная небольшая функция оптимизируется во встроенную функцию), задача G будет выполняться до тех пор, пока не завершится сама собой, если это бесконечный цикл и GOMAXPROCS=1. Тогда всегда будет только один P и один M, а остальные G в очереди выполняться не будут!
Например, следующий код,hello world
не будет выводиться
func main(){
runtime.GOMAXPROCS(1)
go func(){
fmt.Println("hello world")
// panic("hello world") // 强制观察输出
}()
go func(){
for {
// fmt.Println("aaa") // 非内联函数,这行注释打开,将导致 hello world 的输出
}
}()
select {}
}
восстановление после перерыва
- При прерывании сохранять информацию о стеке в регистре в собственный G-объект
- Когда придет ваша очередь выполнять снова, скопируйте сохраненную вами информацию о стеке в регистр, чтобы продолжить операцию после последнего раза.
GOMAXPROCS — Настройка производительности
После прочтения вышеприведенного содержания, я думаю, вы уже знаете,GOMAXPROCS
Это функция пакета среды выполнения в go. Он устанавливает максимальное количество Ps. Это напрямую приводит к максимальному количеству M, а количество M определяет, сколько M потоков может быть вызвано и выполнено каждой очередью G одновременно!
Поэтому мы обычно устанавливаем количество GOMAXPROCS равным количеству ядер ЦП, и следует отметить, что:
- GOMAXPROCS до версии 1.5 по умолчанию равен 1.
- GOMAXPROCS после версии go 1.5 по умолчанию использует Num of cpu.