В презентации Google I/O 2012 – Шаблоны параллелизма в Go, Роб Пайк упоминает, что несколько горутин могут находиться в одном потоке. Означает ли это, что они реализованы как сопрограммы? Если нет, то как они реализуются? Ссылки на исходный код приветствуются.
Является ли горутина Go сопрограммой?
Ответы (4)
Не совсем. В разделе FAQ по Go Почему горутины вместо потоков? поясняется:
Горутины являются частью упрощения использования параллелизма. Идея, которая существует уже некоторое время, состоит в том, чтобы мультиплексировать независимо выполняющиеся функции — сопрограммы — в набор потоков. Когда сопрограмма блокируется, например, вызывая блокирующий системный вызов, среда выполнения автоматически перемещает другие сопрограммы в том же потоке операционной системы в другой исполняемый поток, чтобы они не были заблокированы. Программист ничего этого не видит, в этом и смысл. Результат, который мы называем горутинами, может быть очень дешевым: у них мало накладных расходов, кроме памяти для стека, которая составляет всего несколько килобайт.
Чтобы сделать стеки небольшими, во время выполнения Go используются ограниченные стеки изменяемого размера. Новоиспеченной горутине дается несколько килобайт, чего почти всегда хватает. Когда это не так, среда выполнения автоматически увеличивает (и сжимает) память для хранения стека, позволяя многим горутинам жить в скромном объеме памяти. Накладные расходы ЦП составляют в среднем около трех дешевых инструкций на вызов функции. Практично создавать сотни тысяч горутин в одном и том же адресном пространстве. Если бы горутины были просто потоками, системные ресурсы исчерпали бы гораздо меньше.
ИМО, сопрограмма подразумевает поддержку явных средств для передачи управления другой сопрограмме. То есть программист программирует сопрограмму таким образом, когда он решает, когда сопрограмма должна приостановить выполнение и передать управление другой сопрограмме (либо путем ее вызова, либо путем возврата/выхода (обычно называемого уступкой)).
Горутины Go — это другое дело: они неявно передают управление в определенных неопределенных точках1, которые происходят, когда горутина собирается заснуть на каком-то (внешнем) ресурсов, таких как завершение ввода-вывода, отправка канала и т. д. Этот подход в сочетании с обменом состоянием по каналам позволяет программисту писать логику программы в виде набора последовательных облегченных процессов, что устраняет распространенную проблему спагетти-кода. как к сопрограммам, так и к подходам, основанным на событиях.
Что касается реализации, я думаю, что они очень похожи на (к сожалению, не слишком известную) библиотеку State Threads, просто на более низком уровне (поскольку Go не полагается на libc
или подобные вещи и взаимодействует напрямую с ядром ОС) — вы можете прочитать вводный документ по библиотеке ST, где концепция довольно хорошо объяснена.
1 На самом деле эти точки менее определены, чем у сопрограмм, но более определены, чем у настоящих потоков ОС в упреждающая многозадачность, при которой каждый поток может быть приостановлен ядром в любой заданный момент времени и в потоке управления потоком.
Обновление от 28 мая 2021 г. : на самом деле, начиная с Go 1.14, горутины планируются (почти) упреждающе . Однако следует отметить, что это все еще не то самое жесткое вытеснение, которое обычное ядро делает с потоками, которыми оно управляет, но оно гораздо ближе, чем раньше; по крайней мере, теперь горутина не может стать невыгружаемой после входа в цикл занятости.
Является ли горутина правильной сопрограммой или чем-то похожим, часто обсуждается на https://groups.google.com/forum/?fromgroups=#!forum/golang-nuts. Кто-то может поспорить о таких тонкостях, но для большинства так: горутина есть сопрограмма.
Взгляните на https://docs.google.com/document/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw/edit чтобы понять, как работает планировщик.
Горутина — это отдельный «поток» выполнения. Это ИМО не совсем сравнимо с сопрограммой. В первом приближении горутины могут быть реализованы настоящими потоками ОС. Насколько я знаю, так было с ранними версиями gccgo. Еще одно отличие состоит в том, что горутины могут быть вытеснены.
Текущие компиляторы Go реализуют горутины как очень легкие «потоки» пользовательского пространства. Одна отличительная особенность, например. зеленые потоки заключается в том, что горутины могут переключаться на разные потоки ОС.
Я думаю, вы можете найти некоторые интересные моменты здесь: proc.c
preempted
?
- person Sławosz; 05.08.2013