Comments 59
Лайк, познавательное чтиво
Спасибо за титанический труд!
Один из лучших материалов по данной теме! Спасибо, Николай!
Николай, как всегда, в своем уникальном стиле. Опять выпустил лучший материал по теме!
Отличная статья, спасибо. Ждём книгу.
Вспомнил пароль от хабра, только чтобы сказать "лайк!" :) Оч круто, спасибо
Отличный разбор. Подробно и наглядно. Не зря столько ждали!
Есть стойкое подозрение что автор понятия threads and processes то-ли путает, то-ли недосказывает.
« Горутины же мы можем построить таким образом, чтобы они были намного более легковесными по памяти и, самое главное — чтобы переключение между ними было гораздо дешевле, чем переключение между тредами. Это возможно, потому что все они будут жить внутри одного процесса (нашей программы) и иметь общий доступ к памяти, а переключение между ними будет»
Вроде как threads живут внутри одного процесса и из для того и сдали чтобы экономит. Время на переключение между процессами.
Опять-таки, если не ошибаюсь, то это process модно привязать к конкретному ядру процессора, чтобы избежать потерь времени на переключение между ядрами.
Далее для нормальной производительности у вас должно быть X processes , где Х = числу ядер процессора, каждый процесс в идеале должен быть привязан к своему ядру.
Каждый процесс должен запускать Y threads, внутри которых вы можете делать свои Lightweight threads/ go routines.
Рекомендую оригинальную презентацию Роберта Пайка :
https://talks.golang.org/2012/waza.slide
У нег кстати нет понятия thread, есть понятие process в широком смысле слова.
Опять-таки, если не ошибаюсь, то это process модно привязать к конкретному ядру процессора, чтобы избежать потерь времени на переключение между ядрами.
Поток на логическое ядро, и в нем уже горутины, управляемые планировщиком.
Николай, если книга будет в подобном стиле написана, то она точно будет на полках лежать в разделе must read)
Похоже недопонимание у вас. Вы ссылаетесь на Windows модель, в то время как в Linux она совершенно другая. «Once upon a time there was Unix and in this good old Unix there was lots of overhead for processes, so what some clever people did was to create threads, which would share the same address space with the parent process and they only needed a reduced context switch, which would make the context switch more efficient.
In a contemporary Linux (2.6.x) there is not much difference in performance between a context switch of a process compared to a thread (only the MMU stuff is additional for the thread). There is the issue with the shared address space, which means that a faulty pointer in a thread can corrupt memory of the parent process or another thread within the same address space.»
И как вам в ссылке показали - создатель Go -Пайк говорит о «процессах» в общем смысле а не о threads.
Специально залез в MSDN: setprocessaffinity, setthreadaffinity:
“A thread affinity mask is a bit vector in which each bit represents a logical processor that a thread is allowed to run on.
A thread affinity mask must be a subset of the process affinity mask for the containing process of a thread.
A thread can only run on the processors its process can run on.
Therefore, the thread affinity mask cannot specify a 1 bit for a processor when the process affinity mask specifies a 0 bit for that processor.”
Он прав в том смысле, что и в этом посте и в телеграме действительно есть мутные определения, которые вызываеют вопросы.
И цитату про он привёл характерную, про то, что "горутины-то не то, что потоки, они-то живут внутри одного адресного пространства". Это действительно наводит на мысли о недопонимании.
Цитаты же
«Процессы — это, по сути, выполняющиеся программы. Это всё, что о них пока необходимо знать.»
"чем процесс отличается от треда. В таком случае, можете добавить, что процессы друг от друга изолированы, т.е. не имеют доступ к памяти друг друга. Более умным языком - каждый процесс работает в своём собственном виртуальном адресном пространстве, которое изолируется на уровне ОС."
Тоже меня лично смущают. из них можно сделать вывод, что процессы и потоки -- это объекты схожей природы и можно одно заменять другим, что не так.
Поток -- всегда дочерняя сущность одного и только одного процесса. В любом процессе всегда есть хотя бы один поток.
Процесс -- это про виртуальное адресное пространство, метаинфу вроде переменных среды и взаимодействие с операционной системой в плане доступов.
Поток -- это про значения набора регистров (это и есть тот самый контекст) и про планировщик.
С точки зрения linux нет разницы между процессами и тредами для него они неразличимые единицы планирования, для терминологии го, thread мепится на M, и экономится не на переключении между ядрами процессоров, а на переключении между режимами пользователя и ядра ОС. При этом до момента запуска неизвестно на каком системном треде запустится горутина когда планировщик го её подхватит, в этот момент с го сущностью процессора P может быть ассоциирован произвольный тред ОС
С точки зрения Go нет понятия thread- есть понятие процесс. Выше я скидывал ссылку на презентацию Пайка , где он объясняет как concurrency в Го работает. Автор решил пересказать своими словами и использует терминологии которая как минимум не правильная в приложении к Go, и употребляется в совершенно другом контексте.
Я уже приводил цитату из поста:
« Горутины же мы можем построить таким образом, чтобы они были намного более легковесными по памяти и, самое главное — чтобы переключение между ними было гораздо дешевле, чем переключение между тредами. Это возможно, потому что все они будут жить внутри одного процесса (нашей программы) и иметь общий доступ к памяти, а переключение между ними будет»
Где автор явно путает thread, process , где go-routine находится и кто к чему имеет доступ.
В общем все по классике:
«Кто на ком стоял? Изволите выражаться яснее»
Далее « Во-вторых, каждый тред отъедает существенную часть памяти нашего компьютера: стек каждого треда часто может занимать до пары мегабайт (в нём хранятся локальные переменные, цепочки вызова функций и др.)»
Это процесс хранит данные и изолирует из от других процессов в ОС. Идея threads - избежать дорогих процессов и иметь возможность «расшарить» данные между threads в одном процессе.
Спасибо за статью! Отличный стиль изложения, напомнило бандитскую классику (GoF).
Читается легко, но серьёзно.
Надеюсь, эта статья станет одной из глав в книге про Go
Интересная и качественная статья. Спасибо автору за труд!
Спасибо за качественный материал! Очень жду книгу)
Мои уважение и благодарность за проделанную работу🙇
Не успел 2 часовое видео посмотреть по этой же теме от этого же автора, а тут еще и статься вышла, топчик
Николай, спасибо за труды. Полез вспоминать пароль от хабра чтобы поставить лайк.
Николай, Вы большой молодец! Спасибо за труд! вошел в аккаунт специально чтобы поставить лайк).
Спасибо огромное Николаю! Материал лучший.
Отдельное спасибо за прекрасные иллюстрации!
ух, мощно. Это прям талант писать такие сложные, огромные штуки так доходчиво
Спасибо за статью! После видео легко зашла, прочиталась на одном дыхании + уточнил для себя пару моментов, которые из видоса позабыл
В других материалах вы могли также видеть определения kernel space (пространство ядра) и user space (пространство пользователя). Так вот — горутины будут существовать в user space, то есть ими управляет планировщик Go (если точнее — Go Runtime), а треды в kernel space, то есть ими управляет ОС.
Упоминаемые треды существуют в user space и к kernel space не имеют отношения.
И ещё много чего... Чтобы выпустить книгу потребуется хороший технический редактор.
Просто формулировка немного неточная получилась, под "существуют" я имел в виду это:
Так вот — планирование горутин происходит на уровне user space, то есть ими управляет планировщик Go (если точнее — Go Runtime), а планирование тредов на уровне kernel space, то есть ими управляет ОС.
Так устроит?
И ещё много чего...
Внимательно слушаю, что ещё?
Как уже писал: не используйте само придуманных названий. Есть устоявшаяся терминология: в Го, Erlang и других языках которые базируются на идее Communication Sequantial Processes - используется понятие Процесс. Обычно говориться то в отличии от OS процесса- он является light-weighted. Этого достаточно для понимания и устраняет двусмысленность
Дальше тоже интересно:
“Порядок проверки очередей
Теперь у нас есть два типа очередей - LRQ и GRQ. Соответственно, каждый Процессор может брать работу в двух местах, а значит нам нужно определиться, в каком порядке он будет это делать.
Очевидно, что сначала Процессор будем заглядывать в LRQ, ведь она самая быстрая, именно ради этого мы её и ввели. Но если там пусто, то далее Процессор заглянет в GRQ.
Правда, тут может возникнуть ещё одна проблема — если LRQ всех процессоров постоянно пополняется, то Процессоры всегда будут брать работу оттуда, и никогда не доберутся до GRQ. Это плохо, потому что горутины в глобальной очереди начнут застаиваться, поэтому нам стоит иногда проверять её вне очереди. Но как часто? Очевидно, один раз из 61!”
Раздачу go рутин по очередям вроде как планировщик должен осуществлять а не сам процесс.
Раздачу go рутин по очередям вроде как планировщик должен осуществлять а не сам процесс
Дяденька, а вы точно настоящий сварщик..?
Вроде да:
https://github.com/golang/go/blob/master/src/runtime/proc.go
// Goroutine scheduler
// The scheduler's job is to distribute ready-to-run goroutines over worker threads.
//
// The main concepts are:
// G - goroutine.
// M - worker thread, or machine.
// P - processor, a resource that is required to execute Go code.
// M must have an associated P to execute Go code, however it can be
// blocked or in a syscall w/o an associated P.
Можете конечно сами код посмотреть но я бы и комментариям поверил
Че за душнила
Как уже писал: не используйте само придуманных названий. Есть устоявшаяся терминология: в Го, Erlang и других языках которые базируются на идее Communication Sequantial Processes - используется понятие Процесс. Обычно говориться то в отличии от OS процесса- он является light-weighted. Этого достаточно для понимания и устраняет двусмысленность
Сначала дайте определение вашей терминологии а потом навязывайте ее. Что за light-weighted process? Чем он отличается от треда? От горутины?
Раздачу go рутин по очередям вроде как планировщик должен осуществлять а не сам процесс.
Где противоречие этому в тексте сверху? Там нет ни одного слова про раздачу по очередям. Есть только про взятие из очередей.
годнота
Я бы еще доклад от создателя этого планировщика добавил, откуда автор явно черпал вдохновение
Отличная статья. Спасибо!
Очень интересно! Огромное вам спасибо! Жду следующую часть!
Спасибо, что почти везде используете термин "тред", а не "поток". Так гораздо лучше
Здравствуйте, спасибо за статью. Я использую простой пример при пояснении конкурентности и параллелизма - мы сами (люди то бишь). Человек мыслит конкурентно, обдумывая только 1 вещь в один момент времени, но при этом люди думают о разных или одинаковых вещах в одно и то же время.
Ллмка пишет что неблокирующие системные вызовы на чтение файлов есть и в линкусе и в винде, похоже на правду.
Отличная статья, спасибо большое!
Хотел спросить, куда деваются горутины, которые освободили управление через проверку флага stackguard
? Правильно ли я понимаю, что они помещаются в конец локальной очереди выполнения своего процессора?
Очень круто. Появилось понимание качественное. Будем ждать еще статей о тебя) спасибо!
Отличый материал. Замечательно, что матриал представлен в текстовом виде и видео, какждый может выбрать формат удобный для себя или оба.
А что не так с работой с файлами - там же тоже есть неблокирующий API? В Java пилят свои легковесные потоки и вроде как там всё норм работает.
Как минимум, механизмы poll Linux не поддерживают неблокирующийся ввод-вывод для обычных файлов. Есть асинхронный ввод-ввывод, но это уже другая история.
почитал наискосок документацию по poll
/epoll
, но не увидел явного запрета на использовние с файлами - функция оперирует дескрипторамм.
Впрочем из древнего обсуждения на эту тему можно понять, что файлы в Linux не поддерживали (и до сих пор не поддерживают?) poll-интерфейс.

Отличная статья, спасибо большое!
Николай - Легенда! Спасибо за статью
Спасибо, тебя всегда приятно и полезно читать!
Это замечательно! Просто великолепно! Готовлюсь к смене стека на Go, изучаю все ваши видосы и статьи, не всегда сразу понимание, но зато потом как понял...)
Планировщик Go — самый подробный гайд простым языком