Ractors
Настоящий параллелизм
«Ractors» — бесплатный урок Ruby Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Ruby Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Ruby Academy содержит 4 уроков всего.
Что такое актор Ractor
Актор Ractor (актор Ruby) — это примитив конкурентного выполнения, появившийся в Ruby 3 и обеспечивающий настоящий параллелизм. Каждый актор Ractor самостоятельно выполняет код Ruby, поэтому два актора Ractor могут одновременно использовать два ядра CPU.
- Акторы Ractor не используют общие изменяемые объекты, что позволяет обойти ограничение GVL.
- Они обмениваются сообщениями.
Акторы Ractor всё ещё экспериментальны, поэтому Ruby выводит предупреждение при их использовании.
Создание актора Ractor
Создайте его с помощью Ractor.new и блока. Блок выполняется параллельно. Используйте take, чтобы получить итоговое значение блока.
r = Ractor.new do
2 + 3
end
puts r.takeНет общего состояния
Главное правило: акторы Ractor не могут свободно использовать общие изменяемые объекты. Блок актора Ractor не захватывает внешние локальные переменные так, как это делает обычный блок. Данные необходимо передавать явно.
Именно такая изоляция делает параллельное выполнение безопасным без блокировок.
Передача аргументов внутрь
Аргументы Ractor.new передаются параметрам блока. Это безопасный способ передать данные в актор Ractor.
r = Ractor.new(10) do |x|
x * x
end
puts r.takeОтправка сообщений
У акторов Ractor есть входящие сообщения. Отправляйте сообщения с помощью ractor.send(value), а внутри блока принимайте их с помощью Ractor.receive.
r = Ractor.new do
msg = Ractor.receive
"got: " + msg
end
r.send("hello")
puts r.takeОтправка и получение
Два направления обмена данными:
- Отправка: передайте данные в актор Ractor с помощью
send, а прочитайте их с помощьюRactor.receive. - Получение: актор Ractor выдаёт данные с помощью
Ractor.yield, а внешний код читает их с помощьюtake.
Вместе эти возможности позволяют создавать из акторов конвейеры.
r = Ractor.new do
Ractor.yield 1
Ractor.yield 2
end
puts r.take
puts r.takeЗамороженные объекты и объекты, доступные для совместного использования
Некоторые объекты можно использовать совместно в разных акторах Ractor, поскольку их нельзя изменить: true, false, nil, числа, символы и объекты, замороженные вместе со всем содержимым.
Ractor.make_shareable замораживает граф объектов, чтобы им можно было безопасно пользоваться совместно.
data = Ractor.make_shareable([1, 2, 3])
puts "Frozen? " + data.frozen?.to_sКопирование и перемещение
Когда Вы отправляете объект, которым нельзя безопасно делиться, Рактор по умолчанию выполняет его глубокое копирование, чтобы у каждой стороны была собственная копия. Вместо этого его можно переместить с помощью send(obj, move: true): владение передаётся, а исходный объект становится непригодным для использования.
Перемещение позволяет избежать затрат на копирование больших объектов.
Параллельная работа
Распределяйте ресурсоёмкую для CPU работу между раторами и собирайте результаты. Поскольку каждый из них выполняется независимо, это позволяет задействовать несколько ядер.
ractors = (1..3).map do |n|
Ractor.new(n) do |x|
x * 100
end
end
results = ractors.map(&:take)
puts "Results: " + results.join(", ")Ракторы и потоки
Сравнение:
- Потоки используют общую память и требуют блокировок; ракторы изолированы и взаимодействуют с помощью сообщений.
- Потоки не выполняют параллельно вычислительную работу Ruby; ракторы выполняют.
- Ракторы строже, что предотвращает множество ошибок параллелизма.
Компромисс заключается в более жёстких правилах совместного использования данных.
Когда использовать ракторы
Выбирайте ракторы, когда:
- У Вас есть работа, ограниченная производительностью CPU, и Вы хотите задействовать несколько ядер в одном процессе.
- Вам нужна изоляция, чтобы избежать ошибок, связанных с общим состоянием.
Помните, что ракторы являются экспериментальной функцией: API могут измениться, а многие гемы пока не готовы к работе с раторами.
Быстрая проверка
Проверьте своё понимание раторов.
Итоги: ракторы
Вы изучили параллельное выполнение внутри процесса с помощью раторов:
Ractor.newвыполняет код параллельно;takeполучает его результат.- Передавайте данные через аргументы или
send; получайте их с помощьюRactor.receive. - Объекты копируются или перемещаются, а не используются совместно без ограничений.
Ractor.make_shareableзамораживает данные для безопасного совместного использования.
На этом завершается курс по конкурентности Ruby: потоки, GVL, волокна и ракторы.
Часто задаваемые вопросы
Урок «Ractors» бесплатный?
Да — полный текст урока «Ractors» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Ruby Academy, подпишись на CoddyKit PRO. Курс Ruby Academy содержит 4 уроков всего.
Чему я научусь в уроке «Ractors»?
Настоящий параллелизм Ты практикуешь Ruby Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Ruby Academy?
Предыдущий опыт не требуется. Ruby Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Ractors»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Ruby Academy?
Да. Каждый урок Ruby Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Потоки
- Объяснение GVL
- Волокна
- Ractors