Ruby / Rails потокобезопасность - PullRequest
18 голосов
/ 15 марта 2009

Я время от времени взламывал Ruby, но я не делал ничего большого или многопоточного. Я слышал, что MRI поддерживает только зеленые потоки, а JRuby поддерживает собственные потоки через JVM. Тем не менее, я натыкаюсь на комментарии в блогах и дискуссионных группах, которые говорят, что «Rails не является потокобезопасным» или что сам Ruby не является потокобезопасным. Например, кто-то заметил, что есть проблема с требованием утверждения. Это звучит немного фундаментально.

Я видел много Java-приложений, которые не обрабатывают параллелизм должным образом, и время от времени мне снятся кошмары о них :-) Но по крайней мере вы можете писать поточно-ориентированные приложения на Java, если Вы действительно знаете, что делаете (это просто нелегко).

Все это звучит довольно тревожно, может кто-нибудь подробнее уточнить - в чем именно проблема и как Rails удается вообще работать, если это так? Могу ли я написать многопоточный код Ruby, который работает правильно, без условий гонки и тупиков? Это переносимо между JRuby и MRI или мне нужно взломать код, специфичный для JVM, чтобы правильно использовать преимущества собственных потоков JVM?

EDIT:

Мне следовало задать два вопроса, потому что люди, похоже, отвечают только на вопросы о потоках рельсов (что само по себе хорошо) и зеленые потоки против нативных потоков. Мои опасения по поводу основных проблем Ruby в отношении потока безопасность на самом деле не решены. Кажется, по крайней мере (неразрешенная?) проблема с требованием в определенных случаях.

Ответы [ 4 ]

14 голосов
/ 17 марта 2009

Прежде всего, Ruby 1.9 (последний официальный выпуск) теперь использует нативные (ядра) потоки . В предыдущих версиях Ruby использовались зеленые темы. Чтобы кратко ответить на ваш вопрос, до версии 1.9 потоки обычно не использовались в приложениях Ruby, больших или малых, именно потому, что они не особенно безопасны или надежны.

Это не особенно тревожно, потому что до версии 2.2 Rails не пытался быть поточно-ориентированным, и поэтому мы обычно выполняем асинхронную обработку посредством использования нескольких процессов, блокировки записей базы данных и очередей сообщений, таких как Starling, Как правило, это довольно надежный способ масштабирования веб-приложения - по крайней мере, такой же надежный, как неправильно многопоточные Java-приложения, - и имеет дополнительное преимущество, заключающееся в том, что становится легче масштабировать ваше приложение на нескольких процессорах и серверах.

Я понятия не имею, была ли упомянутая вами проблема 'require' решена на 1.9, но я смиренно решаю, что если вам динамически требуются библиотеки в новых потоках, то у вас более одной проблемы с ремонтопригодностью.

Если вы хотите полностью исключить потоки, Ruby 1.9 также поддерживает волокна , которые используют метод совместного использования ничего для параллелизма и, насколько я понимаю, в целом легче писать и поддерживать, чем потоки , Производительность здесь .

6 голосов
/ 15 марта 2009

Я действительно предлагаю вам посмотреть выступление Джима Вейриха на RubyConf 2008 (это очень забавно и познавательно :):

https://www.youtube.com/watch?v=fK-N_VxdW7g

Этот тоже хорош:

http://rubyconf2008.confreaks.com/summer-of-code-rails-thread-safety.html

5 голосов
/ 15 марта 2009

Обычным решением для MRI является запуск нескольких экземпляров Rails, каждый из которых обрабатывает запросы независимо. Так как MRI в любом случае не является многопоточным, вы не можете запустить несколько экземпляров Rails поверх него. Это означает, что вы получаете удар по памяти, поскольку Rails загружается один раз для каждого процесса Ruby.

Поскольку JRuby поддерживает собственные потоки, вы всегда можете запустить несколько экземпляров Rails в одной JVM. Но так как Rails является поточно-ориентированным, вы можете сократить его до единицы, что означает меньшее использование памяти и меньшую JIT-компиляцию.

Чарльз Наттер (JRuby) имеет хорошее резюме .

1 голос
/ 16 марта 2009

Я думаю, что предыдущие плакаты довольно хорошо освещали дела Rails, поэтому я не буду вдаваться в подробности.

Конечно, можно писать потоковые Ruby-приложения. Некоторые проблемы, которые существуют с рубиновыми потоками, заключаются в том, что они «зеленые», поскольку ими управляет виртуальная машина. В настоящее время интерпретатор по умолчанию (MRI) имеет только один истинный системный поток, который должен совместно использоваться всеми потоками, которые интерпретатор контролирует.

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

Что касается вашего вопроса о коде интерпретатора: я так не думаю. AFAIK, вам не нужно делать ничего особенного, чтобы заботиться о потоках JRuby / JVM.

Также: Эта статья закончена на Игвите, в которой подробно рассматривается состояние параллелизма в Ruby.

...