Подтвердить что ты не робот

Безопасность резьбы Ruby/Rails

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

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

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

EDIT:

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

Также: Эта статья над игтитой, которая хорошо рассматривает состояние concurrency в Ruby.