Что такое планировщик GPM в Go?

интервью
Что такое планировщик GPM в Go?

😋 Меня зовут Пинг Е, это проект с открытым исходным кодом, ориентированный на развитие технологии Gopher."иди домой"

Управляемое чтение

Думаю, многие слышали, что язык Go естественным образом поддерживает высокую степень параллелизма, потому что внутри есть сопрограммы (горутины), которые могут запускать в процессе тысячи сопрограмм. Итак, почему достигается такой высокий параллелизм? Тогда вам нужно сначала понять, что такое модель параллелизма.

file

Модель параллелизма

Известный специалист по C++ Херб Саттер однажды сказал, что "бесплатный обед закончился". Чтобы код работал быстрее, полагаться только на более быстрое оборудование больше нельзя.Нам нужно использовать несколько ядер, чтобы раскрыть ценность параллелизма, а цель модели параллелизма — рассказать вам, как взаимодействуют разные исполняющие объекты.

file

Конечно, разные модели параллелизма взаимодействуют по-разному.Существует семь распространенных моделей параллелизма:

  • нити и замки
  • функциональное программирование
  • Кложурный путь
  • actor
  • Процесс коммуникационной последовательности (CSP)
  • параллелизм на уровне данных
  • Лямбда Архитектура

Сегодня мы говорим только о модели параллелизма CSP, относящейся к языку Go.Заинтересованные студенты могут самостоятельно обратиться к книге «Seven Weeks Seven Concurrency Model».

file

Статьи CSP

CSP, полное название Communicating Sequential Processes, означает последовательный процесс связи.Это одна из семи моделей параллелизма.Его основная концепция заключается в соединении двух одновременно выполняемых объектов через канал канала, и все сообщения передаются через канал. Фактически концепция CSP была принята еще в 1978 году.Тони ХоллПредполагается, что из-за недавнего появления языка Go CSP снова стал популярным.

Итак, какое отношение CSP имеет к языку Go? Далее рассмотрим реализацию модели параллелизма CSP на языке Go — модель планирования GPM.

file

Модель планирования GPM

GPM представляет три роли, а именно горутину, процессор и машину.

file

  • Горутина: это исполнительный орган, созданный с помощью ключевого слова go, которое мы обычно используем.Он соответствует структуре g, и структура хранит информацию о стеке горутины.
  • Машина: представляет поток операционной системы.
  • Процессор: указывает процессор, с помощью которого может быть установлено соединение между G и M.

Goroutine

Горутина — это исполняющая единица, созданная с помощью ключевого слова go в коде. Это также известная сопрограмма, известная как «облегченный поток». Сопрограммы не известны операционной системе. Они реализованы на уровне языка программирования и переключения контекста. , Нет необходимости проходить состояние ядра, а место в памяти, занимаемое сопрограммой, очень мало, поэтому у нее очень большой потенциал развития.

go func() {}()

В языке Go горутина состоит изruntime.goСтруктура указывает на то, что структура очень сложная, с более чем 40 переменными-членами, которые в основном хранят стек выполнения, состояние, текущие занятые потоки и данные, связанные с планированием. Так же есть логотип goroutine, который все хотят получить, но извините, учитывая развитие языка Go, официалы установили его как приватный, и называть его вам не будут 😏.

type g struct {
	stack struct {
		lo uintptr
		hi uintptr
	} 							// 栈内存:[stack.lo, stack.hi)
	stackguard0	uintptr
	stackguard1 uintptr

	_panic       *_panic
	_defer       *_defer
	m            *m				// 当前的 m
	sched        gobuf
	stktopsp     uintptr		// 期望 sp 位于栈顶,用于回溯检查
	param        unsafe.Pointer // wakeup 唤醒时候传递的参数
	atomicstatus uint32
	goid         int64
	preempt      bool       	// 抢占信号,stackguard0 = stackpreempt 的副本
	timer        *timer         // 为 time.Sleep 缓存的计时器

	...
}

Данные, относящиеся к планированию Goroutine, хранятся в sched, который используется, когда сопрограмма переключает и восстанавливает контекст.

type gobuf struct {
	sp   uintptr
	pc   uintptr
	g    guintptr
	ret  sys.Uintreg
	...
}

Machine

M – это поток, соответствующий операционной системе. Максимальное количество активных потоков GOMAXPROCS, которые могут нормально работать, не должно превышать числа. По умолчанию для GOMAXPROCS установлено количество ядер. Если ядер четыре, то по умолчанию создается четыре потока, а каждый поток соответствует структуре среды выполнения. Причина, по которой количество потоков равно количеству ЦП, заключается в том, что когда каждый поток выделяется ЦП, не будет переключения контекста потока, что может гарантировать минимизацию системных накладных расходов.

type m struct {
	g0   *g 
	curg *g
	...
}

В M есть еще две важные вещи: g0 и curg.

  • g0: будет активно участвовать в процессе планирования во время выполнения, таком как создание горутины, выделение памяти и т. д.
  • curg: представляет горутину, выполняемую в данный момент в потоке.

Я только что сказал, что P отвечает за связь между M и G, поэтому M также хранит данные, относящиеся к P.

type m struct {
  ...
	p             puintptr
	nextp         puintptr
	oldp          puintptr
}
  • p: процессор, на котором выполняется код
  • nextp: временный процессор
  • old: процессор потока перед системным вызовом

Processor

Процессор отвечает за связь между машиной и горутиной, он может предоставить контекст, требуемый потоком, а также может назначить G потоку, который он должен выполнить, с ним каждый G может быть вызван разумно, и каждый поток не длиннее Рыбалка в мутной воде – неотъемлемая часть дома.

file

Точно так же количество процессоров также установлено по умолчанию в соответствии с GOMAXPROCS, что соответствует количеству потоков один за другим.

type p struct {
	m           muintptr

	runqhead uint32
	runqtail uint32
	runq     [256]guintptr
	runnext guintptr
	...
}

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

Отношения троих

Сначала по умолчанию запускаются четыре потока и четыре процессора, а затем привязываются друг к другу.

file

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

file

Что, создал еще одну G? Потом вставляй по очереди в другие П. Я считаю, что когда ты стоишь в очереди на получение номера, ты пройдешь мимо, когда никого не увидишь в другом окне.

file

Что делать, если Gs много и все они заполнены? Затем вместо того, чтобы помещать G в частную очередь процессора, помещайте его в глобальную очередь (зал ожидания).

file

В дополнение к заполнению сторона M должна выполнять дикую выборку. Сначала перейдите в частную очередь процессора, чтобы получить G для выполнения. Если он будет завершен, он попадет в глобальную очередь. Если он не находится в глобальной очереди, он пойдет на другую обработку.Воровство в очереди устройств,вау,так голодно,это черт!

file

Что делать, если G для выполнения нигде не найден? Затем M отключится от P, потому что он слишком разочарован, а затем заснет (бездействует).

file

Что, если две горутины заблокированы из-за того, что они делают что-то приятное через канал? Должен ли M ждать их завершения, прежде чем продолжить выполнение? Очевидно, что нет, M знаком с этой парой мужчин и женщин Го, но он обернется и найдет другого G для исполнения.

file

системный вызов

Если G делает системный вызов, M также войдет в состояние системного вызова, то этот P здесь тратится впустую, что мне делать? Тонкость этого заключается в том, что P не будет глупо ждать завершения системных вызовов G и M, а найдет другие простаивающие M для выполнения других G.

file

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

file

Если нет простаивающих процессоров, G можно только вернуть в глобальную очередь для выделения.

file

sysmon

sysmon — наша тетя-уборщица. Это M, также известный как поток мониторинга. Он может работать независимо без P. Он будет просыпаться каждые 20 мкс~10 мс и выходить на очистку. Основная задача — собирать мусор и долго восстанавливать временная блокировка системного планирования.P, выдача упреждающего расписания длительно работающему G и т. д.

пояснение к записи

Тони Холл

Тони Холл , британский ученый-компьютерщик, лауреат премии Тьюринга, разработал бычий алгоритм быстрой сортировки, логику Холла и модель CSP. В 2011 году он был удостоен премии Джона фон Неймана.

file


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

关注我