Сравните накладные расходы на системные вызовы (syscall) в модели с процессами (например, PostgreSQL) и в модели с горутинами (Go).

Ответ

Системный вызов (syscall) сам по себе — это обращение к ядру ОС, и его стоимость не зависит от того, кто его вызвал. Однако накладные расходы, связанные с блокировкой при системном вызове, кардинально различаются.

В этом сравнении модель с горутинами значительно эффективнее.

Модель с горутинами в Go

  1. Планировщик M:N: Go использует собственный планировщик, который отображает M горутин на N потоков ОС. Горутины — это легковесные потоки, управляемые рантаймом Go, а не ядром ОС.
  2. Неблокирующие syscalls: Когда горутина выполняет блокирующий системный вызов (например, чтение из сети), рантайм Go может "увидеть" это. Он открепляет текущий поток ОС (N) от этой горутины и передает его другой готовой к выполнению горутине (M).
  3. Результат: Переключение контекста происходит между горутинами в рамках одного процесса, что чрезвычайно дёшево. Поток ОС не блокируется и продолжает выполнять полезную работу. Это позволяет эффективно обслуживать тысячи одновременных соединений с небольшим количеством потоков ОС.

Модель с процессами в PostgreSQL (классическая)

  1. Процесс на соединение: PostgreSQL по умолчанию создает отдельный процесс ОС для каждого клиентского соединения. Каждый процесс имеет собственное адресное пространство и управляется напрямую ядром ОС.
  2. Блокирующие syscalls: Когда процесс выполняет блокирующий системный вызов, ядро ОС переводит весь процесс в состояние ожидания.
  3. Результат: Чтобы система продолжила выполнять другую работу, ядро должно выполнить полноценное переключение контекста на другой процесс. Это дорогостоящая операция, включающая смену адресного пространства, таблиц страниц памяти и т.д. Из-за этого масштабирование на десятки тысяч одновременных соединений становится проблематичным и ресурсоемким.

Итог

Характеристика Go (горутины) PostgreSQL (процессы)
Единица конкурентности Горутина (легковесная) Процесс (тяжеловесный)
Переключение контекста Дешевое (внутри процесса) Дорогое (между процессами)
Реакция на блокировку Поток ОС выполняет другую горутину Весь процесс блокируется
Масштабируемость Очень высокая Ограниченная

Таким образом, накладные расходы, связанные с конкурентной обработкой блокирующих системных вызов, в Go на порядки ниже, чем в традиционной модели "процесс на соединение".

Ответ 18+ 🔞

Давай разберём эту дичь, как есть. Слушай сюда, а то сейчас мозг набекрень вынесет.

Вот смотри, сам по себе системный вызов — это просто стук в дверь к ядру операционки. Неважно, кто стучит — горутина или целый процесс. Стоимость стука одинаковая, ёпта. Но вся соль-то не в стуке, а в том, что происходит пока ты ждёшь у этой двери, блядь! Вот тут-то и начинается цирк с конями, и разница — просто пиздец.

Go с его горутинами (хитрые жопы)

  1. Планировщик — мастер на все руки. У Го там своя кухня внутри: он M горутин (этих легковесных пиздюков) раскидывает по N настоящим потокам ОС. Горутины — это почти что виртуальные, управляются самим рантаймом, а не ядром.
  2. Системный вызов? Не, не слышали. Допустим, горутина тупо уперлась в блокирующее чтение из сети. Рантайм Го это видит, он не лох. Он берет поток ОС, который эту горутину обслуживал, и говорит: «Иди-ка ты, дружок, поработай с другой горутиной, пока эта тормозит». Поток ОС не блокируется нахуй!
  3. Что в сухом остатке? Переключение между горутинами — это дешевле пареной репы, потому что всё происходит внутри одного процесса. Один поток ОС может ворочать тысячами этих горутинок, и все довольны. Красота, блядь!

Классический PostgreSQL (архаичные распиздяи)

  1. Один клиент — один процесс. По умолчанию Постгрес — тот ещё максималист. Каждое новое соединение — это новый, полновесный, жирный процесс ОС. Со своим адресным пространством, со своими тараканами. Ядро ОС управляет этой оравой напрямую.
  2. Блокировка? Всем спать! Если такой процесс делает блокирующий системный вызов, ядро ОС вешает на него табличку «не беспокоить» и вырубает весь процесс целиком. Весь, Карл!
  3. Итог — пиздец и переключение контекста. Чтобы работа продолжилась, ядру надо сделать полноценное, дорогущее переключение контекста на другой процесс. Это ж надо память поменять, таблицы страниц, регистры — пиздец какой-то! Из-за этой хуйни масштабироваться на десятки тысяч соединений — это как таскать воду в решете: вроде бы и стараешься, а нихуя не эффективно.

Короче, сводная таблица, чтобы совсем доехало

Параметр Go (с горутинами) PostgreSQL (с процессами)
Кто работает Горутина (легковесный пиздёныш) Процесс ОС (тяжеловесный мужик)
Цена переключения Копейки (внутри своего двора) Овердохуища (между разными квартирами)
Если уперлись в I/O Поток ОС пошел другой горутине пирожки печь Весь процесс лег и уснул, как сука
Масштаб Тысячи соединений на нескольких потоках — легко Тысячи процессов — ад для памяти и планировщика ОС

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