😋 Меня зовут Пинг Е, это проект с открытым исходным кодом, ориентированный на развитие технологии Gopher."иди домой"
Управляемое чтение
Думаю, многие слышали, что язык Go естественным образом поддерживает высокую степень параллелизма, потому что внутри есть сопрограммы (горутины), которые могут запускать в процессе тысячи сопрограмм. Итак, почему достигается такой высокий параллелизм? Тогда вам нужно сначала понять, что такое модель параллелизма.
Модель параллелизма
Известный специалист по C++ Херб Саттер однажды сказал, что "бесплатный обед закончился". Чтобы код работал быстрее, полагаться только на более быстрое оборудование больше нельзя.Нам нужно использовать несколько ядер, чтобы раскрыть ценность параллелизма, а цель модели параллелизма — рассказать вам, как взаимодействуют разные исполняющие объекты.
Конечно, разные модели параллелизма взаимодействуют по-разному.Существует семь распространенных моделей параллелизма:
- нити и замки
- функциональное программирование
- Кложурный путь
- actor
- Процесс коммуникационной последовательности (CSP)
- параллелизм на уровне данных
- Лямбда Архитектура
Сегодня мы говорим только о модели параллелизма CSP, относящейся к языку Go.Заинтересованные студенты могут самостоятельно обратиться к книге «Seven Weeks Seven Concurrency Model».
Статьи CSP
CSP, полное название Communicating Sequential Processes, означает последовательный процесс связи.Это одна из семи моделей параллелизма.Его основная концепция заключается в соединении двух одновременно выполняемых объектов через канал канала, и все сообщения передаются через канал. Фактически концепция CSP была принята еще в 1978 году.Тони ХоллПредполагается, что из-за недавнего появления языка Go CSP снова стал популярным.
Итак, какое отношение CSP имеет к языку Go? Далее рассмотрим реализацию модели параллелизма CSP на языке Go — модель планирования GPM.
Модель планирования GPM
GPM представляет три роли, а именно горутину, процессор и машину.
- Горутина: это исполнительный орган, созданный с помощью ключевого слова 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 может быть вызван разумно, и каждый поток не длиннее Рыбалка в мутной воде – неотъемлемая часть дома.
Точно так же количество процессоров также установлено по умолчанию в соответствии с GOMAXPROCS, что соответствует количеству потоков один за другим.
type p struct {
m muintptr
runqhead uint32
runqtail uint32
runq [256]guintptr
runnext guintptr
...
}
В дополнение к полям, связанным с отслеживанием производительности, сборкой мусора и таймерами, в структуре P также хранится очередь для выполнения процессором, а в очереди хранится список горутин для выполнения.
Отношения троих
Сначала по умолчанию запускаются четыре потока и четыре процессора, а затем привязываются друг к другу.
В это время создается структура Goroutine.После обновления адреса тела функции, начального адреса параметра, длины параметра и другой информации и атрибутов, связанных с планированием, он войдет в очередь процессора и будет ждать отправления.
Что, создал еще одну G? Потом вставляй по очереди в другие П. Я считаю, что когда ты стоишь в очереди на получение номера, ты пройдешь мимо, когда никого не увидишь в другом окне.
Что делать, если Gs много и все они заполнены? Затем вместо того, чтобы помещать G в частную очередь процессора, помещайте его в глобальную очередь (зал ожидания).
В дополнение к заполнению сторона M должна выполнять дикую выборку. Сначала перейдите в частную очередь процессора, чтобы получить G для выполнения. Если он будет завершен, он попадет в глобальную очередь. Если он не находится в глобальной очереди, он пойдет на другую обработку.Воровство в очереди устройств,вау,так голодно,это черт!
Что делать, если G для выполнения нигде не найден? Затем M отключится от P, потому что он слишком разочарован, а затем заснет (бездействует).
Что, если две горутины заблокированы из-за того, что они делают что-то приятное через канал? Должен ли M ждать их завершения, прежде чем продолжить выполнение? Очевидно, что нет, M знаком с этой парой мужчин и женщин Го, но он обернется и найдет другого G для исполнения.
системный вызов
Если G делает системный вызов, M также войдет в состояние системного вызова, то этот P здесь тратится впустую, что мне делать? Тонкость этого заключается в том, что P не будет глупо ждать завершения системных вызовов G и M, а найдет другие простаивающие M для выполнения других G.
Когда G завершает системный вызов, поскольку он хочет продолжить выполнение, он должен найти другой незанятый процессор, чтобы запустить машину.
Если нет простаивающих процессоров, G можно только вернуть в глобальную очередь для выделения.
sysmon
sysmon — наша тетя-уборщица. Это M, также известный как поток мониторинга. Он может работать независимо без P. Он будет просыпаться каждые 20 мкс~10 мс и выходить на очистку. Основная задача — собирать мусор и долго восстанавливать временная блокировка системного планирования.P, выдача упреждающего расписания длительно работающему G и т. д.
пояснение к записи
Тони Холл
Тони Холл , британский ученый-компьютерщик, лауреат премии Тьюринга, разработал бычий алгоритм быстрой сортировки, логику Холла и модель CSP. В 2011 году он был удостоен премии Джона фон Неймана.
Спасибо за просмотр.Если вы считаете, что статья была вам полезна, обратите внимание на паблик-аккаунт "Pingye", посвященный языку Go и техническим принципам.