Механизм планирования сопрограмм Golang и настройка производительности GOMAXPROCS

задняя часть Go GitHub Тенсент
Механизм планирования сопрограмм Golang и настройка производительности GOMAXPROCS

Автор: Линь Гуаньхун / Призраки под рукой

Самородки:Наггетс Талант /user/178526…

Блог:www.cnblogs.com/linguanh/

Гитхаб:GitHub.com/afan913337456…

Облачная колонка Tencent:cloud.Tencent.com/developer/U…


пролог

Правильное понимание взаимосвязи между G, M и P может дать более глубокое понимание механизма планирования сопрограмм! В этой статье будет полностью представлен механизм планирования сопрограмм go, в том числе:

  • Основные компоненты объекта календарного планирования
  • Отношения и разделение труда между объектами
  • Как выполняются горутины
  • Управление системным потоком ядра горутины
  • goroutine coroutine прерывание приостанавливает и возобновляет
  • Как GOMAXPROCS влияет на производительность параллелизма

Кстати: моя техническая книга «Практика разработки блокчейн-приложений на Ethereum» опубликована и может быть приобретена в Интернете.

содержание

Три основных объекта планировщика:

Golang называют Go, Go's协程(goroutine)и наше общее线程(Thread)Мол, есть свой планировщик.

  • G (Горутина) означает сопрограмму, которая используется в каждом коде.go 关键词объект, который будет создан, когда
  • M (рабочая нить), рабочая нить
  • P (процессор), представляющий处理器, он же контекст

Взаимосвязь и характеристики трех G-M-P:

  • Каждый запущенный M должен быть привязан к P. После создания потока M он проверит и выполнит объект G (горутина).
  • Каждый P содержит сопрограмму G队列
  • В дополнение к очереди G, которую содержит каждый P, планировщик также имеет глобальную очередь G.
  • М от队列中Извлеките G и выполните
  • Число PGOMAXPROCS(максимум 256), фиксируется при запуске, в основном не модифицируется
  • Количество M не обязательно совпадает с количеством P (будут спящие M или P, не привязанные к M) (максимум 10000)
  • P хранится в глобальном массиве (255) и поддерживает глобальный список свободных P

Связь между локальной очередью G и глобальной очередью G

  • Глобальная очередь задач G будет обмениваться с каждой локальной очередью задач G в соответствии с определенной стратегией. Верно协程任务обмен
  • Порядок выполнения задачи G заключается в том, чтобы сначала найти ее в локальной очереди, а затем в локальной очереди, если она недоступна локально.全局队列Находить
  • перечислить
    • Локальный и глобальный, глобальный номер G / номер P
    • Местный и местный, передача половины за один раз

Горутина от постановки в очередь до исполнения

  1. Когда мы создаем объект G, этоgorutine, он будет добавлен в локальную очередь или глобальную очередь
  2. Если еще есть свободная P, создайте M, чтобы связать P, обратите внимание! Здесь P не должен был быть связан с M ранее, иначе условие бездействия не будет выполнено. Точки детализации:
    1. Сначала найдите свободный P, если нет, вернитесь напрямую
    2. Количество P не будет занимать больше, чем количество процессоров, установленное вами
    3. После того, как P свяжется с M, он инициализирует свою собственную очередь G, которая является空队列
    4. Обратите внимание здесь一个点!
      • Независимо от того, в каком M G создается, пока P свободен, это приведет к созданию нового M
      • Нет необходимости рассматривать, заполнена ли очередь G связанного P в текущем M
      • Очередь инициализации P, привязанная к вновь созданному M, будет извлекать задачи из других очередей G.
    5. Это оставляет первый вопрос:

      Если время выполнения задачи G слишком велико, она всегда будет занимать потоки M. Поскольку задачи G в очереди выполняются последовательно, другие задачи G будут заблокированы. Как избежать этой ситуации? --①

  3. М начнет底层线程,循环执行G задач, которые можно найти. Вот G, который нужно искать в следующих аспектах:
    • найти в очереди P, к которой привязан текущий M
    • Перейдите в очередь других P, чтобы найти
    • Перейдите в глобальную очередь G, чтобы найти
  4. Порядок выполнения задачи G заключается в том, чтобы сначала найти ее в локальной очереди и найти в глобальной очереди, если локальной очереди нет.
  5. Когда программа запускается, сначала запускается основной поток, а затем основной поток связывает первый P
  6. Основная функция входа фактически выполняется как горутина.

Ответь на вопрос-①

Квант времени переключения сопрограммы составляет 10 мс, что означает, что горутина будет переключена на следующий G на M, когда она будет выполняться не более 10 мс. Этот процесс также называется中断,挂起

принцип:

Когда программа go запускается, она сначала создает специальный поток ядра.sysmon, используемый для мониторинга и управления, а его внутренняя часть представляет собой цикл:

  1. Запишите все задачи P's of G计数 schedtick, метка расписания будет увеличиваться после выполнения каждой задачи G

  2. Если отмеченоschedtickОн не был увеличен, что указывает на то, что этот P выполнял ту же задачу G. Если он превышает 10 мс, добавьте тег tag в информацию о стеке этой задачи G.

  3. Затем, когда выполняется задача G, если она встречает не встроенный вызов функции, она один раз проверит флаг, затем прервет себя, добавит себя в конец очереди и выполнит следующий вызов G.

  4. если не встретится非内联函数Если она вызывается (иногда обычная небольшая функция оптимизируется во встроенную функцию), задача 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 {}
}

восстановление после перерыва

  1. При прерывании сохранять информацию о стеке в регистре в собственный G-объект
  2. Когда придет ваша очередь выполнять снова, скопируйте сохраненную вами информацию о стеке в регистр, чтобы продолжить операцию после последнего раза.

GOMAXPROCS — Настройка производительности

После прочтения вышеприведенного содержания, я думаю, вы уже знаете,GOMAXPROCSЭто функция пакета среды выполнения в go. Он устанавливает максимальное количество Ps. Это напрямую приводит к максимальному количеству M, а количество M определяет, сколько M потоков может быть вызвано и выполнено каждой очередью G одновременно!

Поэтому мы обычно устанавливаем количество GOMAXPROCS равным количеству ядер ЦП, и следует отметить, что:

  • GOMAXPROCS до версии 1.5 по умолчанию равен 1.
  • GOMAXPROCS после версии go 1.5 по умолчанию использует Num of cpu.