tgoop.com/careerunderhood/348
Last Update:
CPU, Memory Models, Concurrency, Multiprocess, Multithreading и Async. Часть 19. Ruby.
Продолжаем разбор языков программирования, сегодня очередь Ruby - языка который одним из первых предложил пользователям возможности асинхронного программирования, во времена когда NodeJS еше толком не существовал.
🔵 Процессы
Создаются с помощью функции fork
. GIL на них не распространяется, за счет чего можно добиться параллелизма на многоядерной системе. Чтобы экономить память при создании многопроцессных программ, стоит не забывать про принцип Copy on Write.
В этот раз примеров кода не будет, будет лучше - небольшая бесплатная книжка, которая классно объясняет как работать с процессами Working with Unix Processes. Этакий симбиоз системного программирования и Rubу. Горячо рекомендую, здорово подойдет для расширения кругозора.
🔵 Потоки
В Ruby есть класс Thread, инстансы которого являются потоками исполнения. Каждый созданный поток мапится на поток ОС (1-1 mapping). Если вы запускаете код на классическом интерпретаторе - параллелизм недостижим из за GIL. Возможна конкурентность, если ваша программа преимущественно работает с IO.
Working with Ruby Threads вместо тысячи слов.
🔵 Fibers + External Fiber Scheduler
Файберы как примитив появились в Ruby достаточно давно и представляют собой что-то вроде генератора в Python или любом другом языке. А если вы помните - вся соль генераторов - ключевое слово yield. Оно подразумевает что контроль исполнения программы передается другой функции. При этом функция-владелец генератора может снова попасть в эту точку входа через вызов next()
в Python
или resume
в Ruby
. Генераторы и файберы это так называемые resumable функции. Штука полезная, но на первый взгляд выглядит как удобный синтаксический сахар, не более. Но это не так😊
Имея такой примитив в языке программирования открывается простор для написания асинхронного кода, ведь нам нужно чтобы при тяжелых и долгих IO операциях была возможность как бы выйти из функции и дать другим файберам делать полезную работу, а потом когда IO будет доступно для работы снова вернуться к функции.
Но сами по себе что файберы что генераторы не дают никаких бенефитов, для того чтобы раскрыть всю мощь, нам нужен рантайм который бы позволял перейти от синхронного взаимодействия к асинхронному. В Python
это asyncio
а вот Ruby
в своей стандартной библиотеке не содержит ничего подобного. Поэтому за дело взялось комьюнити и реализовало много интересных реализаций.
- EventMachine
- Celluloid
- socketry
стек (async
+ io-event
+ falcon
)
- Polyphony
Все эти библиотеки предлагают удобные примитивы высокого уровня позволяющие писать выразительный асинхронный код, скрывая сложные взаимодействия с неблокирующими сокетами, событиями ОС итп. Почему для реализации асинхронных примитивов требуется взаимодействие с ОС подробно рассказал в посте и посте.
Пример асинхронного кода с 2мя задачами, с использованием библиотеки Async
———
В Ruby 3.0 появилась функция Fiber.set_scheduler
позволяющая разработчику подключить сторонний или написать свой собственный планировщик который бы переключал файберы которые создаются в коде.
Если раньше для асинхронщины нам требовалось использовать явно вызовы какого-то гема, то с появлением интерфейса для файбер планировщика программист просто создает задачи через Fiber.schedule
, а их менеджмент проиходит под капотом. Если потребуется использовать другую библиотеку то меняем только одну строчку кода а не перелопачиваем весь проект. Да, возможно было бы приятнее если бы в стандартной библиотеке Ruby появился свой аналог asyncio
, но пока до этого дело не дошло.
Дополнительно отмечу что файберы в Ruby кооперативные, так как переключение происходит при явных вызовах передачи владения или IO задачах (аналогично в asyncio и java virtual threads).
Пример асинхронного кода с 2мя задачами, с использованием Async::Scheduler
P.S. Список доступных планировщиков файберов
P.P.S Если на меня подписаны рубисты, расскажите как сейчас дела с файберами в продакшне?😊
BY Евгений Козлов пишет про IT
Share with your friend now:
tgoop.com/careerunderhood/348