Модель реализации потока
- Модель потоков на уровне пользователя
- Модель потоков на уровне ядра
- Двухуровневая модель потоков
Go Threading основные элементы модели MPG
Поверх потоков ядра, предоставляемых операционной системой, Go строит уникальную двухуровневую модель потоков.
Выполнение G требует поддержки P и M. После связывания P и M формируется эффективная рабочая среда G (поток ядра + контекстная среда).
Каждый P будет содержать очередь исполняемых G, и G в очереди будут переданы текущему M, связанному с локальным P, в свою очередь, и получат время выполнения.
- M
- Аббревиатура для машины, M представляет собой поток ядра в пользовательском пространстве, который всегда соответствует потоку ядра (KSE) один к одному. В течение жизненного цикла M он будет связан только с одним KSE.
- Когда M только что создан, он будет добавлен вГлобальный список M.
- Иногда М будет остановлен (например, когда не будет найдено ни одного работающего G и т. д.), и М будет добавлено кПростой M список дистрибьютора, когда требуется неиспользуемый M, планировщик сначала попытается получить его из этого списка.
- Максимальное значение M, используемое одной программой Go, может быть установлено, а начальное значение равно 10000.
- Старт и стоп М:
Когда M заблокирован из-за системного вызова (точнее, его запущенный G входит в системный вызов), система времени выполнения отделит M от связанного с ним P, если в исполняемой очереди этого P G еще есть ожидающие выполнения очереди, тогда система выполнения перейдет кБесплатный список M планировщикаНайдите в нем свободный М, а если он не найден, создайте новый, а затем этот р будет ассоциирован, чтобы можно было запустить оставшиеся Г.
- p
- Аббревиатура для процессора, P представляет ресурс (контекст), необходимый для выполнения фрагмента кода Go.
- Планировщик позволит P своевременно устанавливать или отключать связи с разными M, чтобы исполняемый G в P мог вовремя получить время выполнения.
- Количество P равно текущему количеству ядер процессора по умолчанию, а для изменения количества P можно использовать функцию runtime.GOMAXPROCS. Число P — это количество запущенных G очередей.
- Когда P больше не связан ни с каким M, а его рабочая очередь G пуста, он помещается вСписок бесплатных P планировщика, когда потребуется свободная P-ассоциация M, она будет взята из этого списка.
- P содержит список свободных G, хранящих некоторые G, которые были запущены. Когда рост достигнет определенного уровня, система выполнения переведет часть G вБесплатный список G планировщикасередина.
- Статус П:
- Pidel:初始化完成,当前p未与m关联,放入**调度器的空闲P列表**里。
- Prunning:当前p已经和某个m关联,m在执行某个g。
- Psyscall:当前p中的被运行的g正在被系统调用
- Pgcstop:调度器停止调度。runtime正在进行GC(runtime会在gc时试图把全局P列表中的P都处于此种状态);有串行运行时任务正在等执行-->停止当前M-->释放本地P-->p为pgcstop
- Pdead:当前P不再被使用(在调用runtime.GOMAXPROCS减少P数量时,多余的P就处于这种状态)
- Любой p в состоянии, отличном от Pdead, будет помещен в Pgcstop, когда система захочет остановить комнату планирования во время выполнения.Он не вернется в исходное состояние, когда планирование включено, но находится в Pidle (та же начальная строка).
- Любой P, не являющийся Pgcstop, может считаться избыточным из-за сжатия глобального списка P и помещается в состояние Pdead, а его работоспособная очередь G будет переведена вЗапускаемая G-очередь планировщика, G в своем свободном списке G также переносится вБесплатная G-очередь планировщикасередина.
- G
- Аббревиатура goroutine, буква G обозначает фрагмент кода go, G — своего рода инкапсуляция кода go Компилятор Go превратит оператор go в вызов внутренней функции newproc и передаст функцию go и ее параметры в качестве параметров к этой функции.
- Вновь созданный G будет добавлен первымГлобальный список GПосле инициализации P добавляется в локальную очередь запуска, может быть, будет храниться в локальном поле runnext P, в этом поле хранится новый пользователь G, чтобы запустить его раньше. Если у вас уже есть runnext G, то и этот придется кинуть Gисполняемая очередь G этого Pконец . Если очередь заполнена, то этот G может быть добавлен только кЗапускаемая G-очередь планировщикасередина.
- Когда оператор go хочет включить G, исполняющая система сначала попытаетсяБесплатный список G от PПолучите готовый G от, чтобы инкапсулировать эту функцию Go. Можно создать новый G только тогда, когда G не может быть получен.
- Система выполнения попытается передать некоторые из свободных G списка планировщика, когда обнаружит, что в локальном P слишком мало свободного G. Если свободная очередь G локального P окажется заполненной, она передаст частьБесплатный список G планировщика.
- всеБесплатный список GВсе первыми вошли последними.
- После того, как G включен, он будет добавлен в рабочую очередь G для P, чтобы дождаться времени выполнения.
- Статус Г:
- Gidle(刚被分配,还未初始化)
- Grunnable(初始化之后,一般在在p本地的可运行队列中等待运行;如果是退出系统调用且能运行的,放入**调度器的可运行G队列**,不能直接运行的G,则放入**调度器的自由G列表**等待被运行)
- Grunning(正在运行)
- Gsyscall(正在执行系统调用,转出系统调用状态且能运行的,放入**调度器的可运行G队列**;不能直接运行的G,则放入**调度器的自由G列表**等待被运行)
- Gwaiting(正在阻塞,被 channel、IO操作、定时器(time.Timer)、time.Sleep等阻塞),在事件到来之后,G被唤醒,进入 - Grunnable,等待被调用,有些被放入**本地p的可运行G队列**,有些被放入**调度器的本地可运行G队列**,还有些被直接运行(如刚进行网络I/O)。
- Gdead(正在闲置,被放入**本地p或者调度器的自由G队列**)
- Gcopystack(表示G的栈正被移动,为啥移动?因为栈的扩展或收缩)
- Gscan(该状态不能单独存在,和其他状态组合在一起形成一个新状态,在GC扫描时发生)
элемент контейнера
Списки, которые не отмечены, являются односвязными списками.
сфера | М список | P список | G очередь/список |
---|---|---|---|
Система времени выполнения | Глобальный список M | глобальный P-список (массив) | Глобальный список G (срез) |
планировщик | Бесплатный список М | бесплатный список P | G Run Queue, свободный список g (2) |
местный р | Запускаемая очередь G, свободный список G (1) |
Расписание раундов планировщика
Часть задач планирования в двухуровневой поточной модели будет выполняться программами вне ядра операционной системы, в Go за эту часть задач планирования отвечает планировщик, а запланированным объектом является MPG.
Один раунд планирования — это основной процесс планировщика Go, который запускается во многих случаях.После серии работ по инициализации при запуске пользовательской программы первый раунд планирования запускается, и G, который инкапсулирует основной планируется запустить. Блокировка, завершение и выход системных вызовов определенного G будут запланированы на один раунд.
- Планировщик определит, заблокирован ли текущий M, и если да, то он немедленно прекратит планирование и остановит текущий M, и не найдет работоспособный G для текущего M. Когда G, которым он заблокирован, становится работоспособным, M пробуждается и продолжает выполнять G.
- Если нет блокировки с задачей G, проверьте, есть ли последовательная задача времени выполнения (необходимо остановить планировщик GO), ожидающая выполнения, остановите текущее M-ожидание завершения выполнения последовательной задачи времени выполнения. Раз, последовательное задание выполнено, и м будет разбужен и еще раз.
- Нет блокировки, нет последовательной задачи во время выполнения, начните поиск G, как только G будет найден, определите, заблокирован ли G с другим M, если да, запустите G с заблокированным M; если нет, запустите G напрямую.
найти G
Первый этап
Сделайте все возможное, чтобы найти исполняемый G: функция runtime.findrunnable возвращает G в состоянии Grunnable. Процесс разделен на 2 этапа, 10 шагов
- шаг 1:
Получите G, который выполняет финализатор, и поместите его в исполняемую очередь G локального P Финализатор — это функция финализации, которая будет выполняться до того, как ассоциированный объект будет собран сборщиком мусора, и за выполнение этой функции будет отвечать специальный G. Планировщик получит G после того, как решит, что задача была завершена, поместит ее в состояние Grunable и поместит в очередь выполнения G локального P.
- шаг 2:
Полученный из локальной очереди исполняемых файлов P G G, возвращает G
- шаг 3:
Получить G из исполняемой очереди G планировщика и вернуть G
- шаг 4:
Получить G от опросчика сетевого ввода-вывода (netpoller) и вернуть G Планировщик получает список G от netpoller, возвращает заголовок G и помещает остальные G в готовую к выполнению очередь G планировщика. Когда G пытается читать или писать в сетевом соединении, базовая программа готовится к этому и переводит G в состояние Gwaiting. Когда все будет готово, базовая программа вернет соответствующее событие, что позволит netpoller немедленно уведомить об этом G. Получение G от netpoller означает получение тех G, которые уже получили уведомления, переводя их в состояние Grunnable и ожидая запуска. Этот тип G не помещается в готовую к выполнению очередь G в P.
- шаг 5:
Получите G от прочего Runnable G Runnable G, верните G Псевдослучайный алгоритм используется для выбора P из глобального списка P, а затем воровать половину G из его undnable G Queue в очередь локального P's Runnable G. И вернуть первый G украден как результат. Процесс выбора р и воровства G повторяется много раз. Предварительное условие: в дополнение к локальному P, есть нестандартный P
Конец первого этапа
вторая стадия
- шаг 6:
Получить G исполняемой задачи с пометкой GC в локальном P: вернуть G Если система находится в фазе маркировки GC и локальный P может использоваться для задачи маркировки GC, она установит G, предназначенный для маркировки GC, удерживаемый локальным P, в Grunnable и вернет G
- шаг 7:
Получите G из готовой к выполнению очереди G планировщика и верните этот G (Почему вы должны искать его снова? Разве шаги 3 и 4 уже не найдены? Есть ли ситуация после 3 и 4, что G будет добавлен в исполняемую очередь G планировщика?) Если исполняемый G все еще не найден, он отсоединит локальный P от текущего M и поместит P в список свободных P планировщика.
- Шаг 8:
Получите Q-Q Queue из каждого списка P в глобальном списке P, вернитесь к G Проверьте глобальный список P, до тех пор, пока вы обнаружите, что P - это запуск G Queue, не пусто, возьмите P из списка IDLE P-планировщика и ассоциируйте с текущим m, затем вернитесь к первому этапу для поиска G.
- шаг 9:
Получите G, который выполняет задачу маркировки GC, и свяжите P, выделенный G для маркировки GC, с текущим M Если система находится в фазе маркировки GC и глобальные ресурсы, связанные с задачей маркировки GC, доступны, планировщик берет P из своего списка свободных P. Если P содержит выделенную маркировку GC, свяжите P с текущим M , а затем Во-вторых поддерживать второй этап
- шаг 10:
Получить G из сетевого ввода-вывода (netpoller) и вернуть Сборщик получает список G от netpoller.В отличие от шага 4, netpoller был инициализирован и операции ввода-вывода выполнены, и он будет блокироваться до тех пор, пока не появятся доступные G. Но если netpoller не был инициализирован или нет операции ввода-вывода, этот шаг будет пропущен.
имя существительное
-
KSE: объект планирования ядра, объект, который может быть запланирован планировщиком ядра, также известный как поток уровня ядра, является наименьшей единицей планирования ядра операционной системы.
-
Системный вызов: это набор стандартных интерфейсов, предоставляемых ядром операционной системы программам пользовательского пространства. Через этот набор интерфейсов программы пользовательского режима могут обращаться к аппаратным устройствам с ограниченным доступом, чтобы запрашивать системные ресурсы, читать и записывать устройства и создавать новые процессы.