Ответ
Системный вызов (syscall) сам по себе — это обращение к ядру ОС, и его стоимость не зависит от того, кто его вызвал. Однако накладные расходы, связанные с блокировкой при системном вызове, кардинально различаются.
В этом сравнении модель с горутинами значительно эффективнее.
Модель с горутинами в Go
- Планировщик M:N: Go использует собственный планировщик, который отображает M горутин на N потоков ОС. Горутины — это легковесные потоки, управляемые рантаймом Go, а не ядром ОС.
- Неблокирующие syscalls: Когда горутина выполняет блокирующий системный вызов (например, чтение из сети), рантайм Go может "увидеть" это. Он открепляет текущий поток ОС (N) от этой горутины и передает его другой готовой к выполнению горутине (M).
- Результат: Переключение контекста происходит между горутинами в рамках одного процесса, что чрезвычайно дёшево. Поток ОС не блокируется и продолжает выполнять полезную работу. Это позволяет эффективно обслуживать тысячи одновременных соединений с небольшим количеством потоков ОС.
Модель с процессами в PostgreSQL (классическая)
- Процесс на соединение: PostgreSQL по умолчанию создает отдельный процесс ОС для каждого клиентского соединения. Каждый процесс имеет собственное адресное пространство и управляется напрямую ядром ОС.
- Блокирующие syscalls: Когда процесс выполняет блокирующий системный вызов, ядро ОС переводит весь процесс в состояние ожидания.
- Результат: Чтобы система продолжила выполнять другую работу, ядро должно выполнить полноценное переключение контекста на другой процесс. Это дорогостоящая операция, включающая смену адресного пространства, таблиц страниц памяти и т.д. Из-за этого масштабирование на десятки тысяч одновременных соединений становится проблематичным и ресурсоемким.
Итог
| Характеристика | Go (горутины) | PostgreSQL (процессы) |
|---|---|---|
| Единица конкурентности | Горутина (легковесная) | Процесс (тяжеловесный) |
| Переключение контекста | Дешевое (внутри процесса) | Дорогое (между процессами) |
| Реакция на блокировку | Поток ОС выполняет другую горутину | Весь процесс блокируется |
| Масштабируемость | Очень высокая | Ограниченная |
Таким образом, накладные расходы, связанные с конкурентной обработкой блокирующих системных вызов, в Go на порядки ниже, чем в традиционной модели "процесс на соединение".
Ответ 18+ 🔞
Давай разберём эту дичь, как есть. Слушай сюда, а то сейчас мозг набекрень вынесет.
Вот смотри, сам по себе системный вызов — это просто стук в дверь к ядру операционки. Неважно, кто стучит — горутина или целый процесс. Стоимость стука одинаковая, ёпта. Но вся соль-то не в стуке, а в том, что происходит пока ты ждёшь у этой двери, блядь! Вот тут-то и начинается цирк с конями, и разница — просто пиздец.
Go с его горутинами (хитрые жопы)
- Планировщик — мастер на все руки. У Го там своя кухня внутри: он M горутин (этих легковесных пиздюков) раскидывает по N настоящим потокам ОС. Горутины — это почти что виртуальные, управляются самим рантаймом, а не ядром.
- Системный вызов? Не, не слышали. Допустим, горутина тупо уперлась в блокирующее чтение из сети. Рантайм Го это видит, он не лох. Он берет поток ОС, который эту горутину обслуживал, и говорит: «Иди-ка ты, дружок, поработай с другой горутиной, пока эта тормозит». Поток ОС не блокируется нахуй!
- Что в сухом остатке? Переключение между горутинами — это дешевле пареной репы, потому что всё происходит внутри одного процесса. Один поток ОС может ворочать тысячами этих горутинок, и все довольны. Красота, блядь!
Классический PostgreSQL (архаичные распиздяи)
- Один клиент — один процесс. По умолчанию Постгрес — тот ещё максималист. Каждое новое соединение — это новый, полновесный, жирный процесс ОС. Со своим адресным пространством, со своими тараканами. Ядро ОС управляет этой оравой напрямую.
- Блокировка? Всем спать! Если такой процесс делает блокирующий системный вызов, ядро ОС вешает на него табличку «не беспокоить» и вырубает весь процесс целиком. Весь, Карл!
- Итог — пиздец и переключение контекста. Чтобы работа продолжилась, ядру надо сделать полноценное, дорогущее переключение контекста на другой процесс. Это ж надо память поменять, таблицы страниц, регистры — пиздец какой-то! Из-за этой хуйни масштабироваться на десятки тысяч соединений — это как таскать воду в решете: вроде бы и стараешься, а нихуя не эффективно.
Короче, сводная таблица, чтобы совсем доехало
| Параметр | Go (с горутинами) | PostgreSQL (с процессами) |
|---|---|---|
| Кто работает | Горутина (легковесный пиздёныш) | Процесс ОС (тяжеловесный мужик) |
| Цена переключения | Копейки (внутри своего двора) | Овердохуища (между разными квартирами) |
| Если уперлись в I/O | Поток ОС пошел другой горутине пирожки печь | Весь процесс лег и уснул, как сука |
| Масштаб | Тысячи соединений на нескольких потоках — легко | Тысячи процессов — ад для памяти и планировщика ОС |
Вот и весь сказ, блядь. Накладные расходы на всю эту движуху с блокировками в Go и в модели «процесс на соединение» отличаются, как небо и земля. В одном случае ты ловко жонглируешь задачами в одной песочнице, в другом — бегаешь между этажами с мешками цемента. Выводы делай сам, ебать.