Вы «опускаете» очень важные детали — именно те детали, из-за которых у нас и завязалась дискуссия.
Другими словами, Вы пытаетесь вывернуться, и сами себе противоречите:
Выше Вы писали:
Точка исполнения всегда одна, и если у вас исполняется какой-то Ruby код, или C код, который вызван из Ruby, то больше ровным счётом ничего в тот самый момент времени не исполняется в рамках процесса. Это собственно хорошо объясняет тот факт, что даже если запустить чтение файлов (например, STDIN, который теоретически может быть бесконечно быстр) в разных потоках, то нагрузка будет только на одно ядро процессора, и никак не затронет другие ядра.
я разъяснил Вам ваше заблуждение — нагрузка может распределятся на разные ядра, это очень важная деталь, без которой MRI потоки (а тем более что они реализованы через native threads) теряют смысл.
Т.е. Вы же не будете отрицать, что в ~99% случаев web-приложениях используются внешние данные — запросы к БД, внешним источникам (IO операции) и тп? Причем, чаще всего эти операции выполняются дольше чем ruby-код. Именно здесь и идет выигрыш, и задействуются дополнительные ядра.
Да и с чего Вы взяли что в приложениях не применяются C-extensions наподобие nokogiri? JSON-parser/encoder'ы? посмотрите Yajl например. Но больше обратите внимание на IO операции.
Давайте разберемся с самого начала:
1. В MRI 1.9 применяются нативные threads. Каждый раз когда создается экземпляр класса Thread — создается нативный thread OS.
2. При выполнении ruby кода (или C-кода внутри ruby) блокируется GIL. Чтобы выполнялся только один thread.
3. IO операции: операции с файлами, сетевые операции — действительно блокируемые.
4. Но до входа в IO операции освобождается GIL (или как Вы называете флаг прерывания), благодаря этому спящие потоки получают управление.
5. Кастомные C-extensions (nokogiri, json parser, etc) которые напрямую не работают с структурами MRI также освобождают GIL
6. В EM совсем другой принцип — есть всего один поток, но все (в идеале) IO операции неблокируемые.
7. EM использует паттерн Reactor — используются средства OS (epoll,select,etc) для опроса дескрипторов, готовых для чтения/записи.
8. В этом случае ruby код должен быть как можно более быстрым, чтобы быстрей вернуть управление реактору.
9. В EM есть еще thread pools, но мы их не рассматриваем, т.к. являются workaround для блокируемых операций (типа клиента mysql).
Ваши заблуждения:
1. C-код (C-extendsions) который не работает с MRI структурами — может освобождать GIL и будет задействовано более одного ядра.
2. EM переключает не на следующего желающего — а на тот блок кода (callback), для дескриптора которого OS сообщает, что готовы данные для чтения, или запись завершена и тп.
Т.к. C-код как правило выполняется достаточно быстро — профит получается небольшой.
Хорошо, согласен. Скажем так: sinatra пытается использовать EM если запущена под EM сервером, но EM не обязателен
Если вернуться к первоначальному вопросу — то sinatra+em и rails+threads разные инструменты, которые нельзя сравнивать напрямую, именно поэтому он у меня и возник, т.к. Вы не озвучили, что имеете в виду именно EM.
Причем тут sinatra и eventmachine. Вы путаете разные понятия. sinatra некоим образом не завязана на EM.
Какая eventmachine может быть, если sinatra запущена, например из под passenger?
Я использую в нагруженном проекте async_sinatra + em + fibers + thin и знаю о чем говорю.
Я Вам это же могу посоветовать почитать, т.к. Вы не правы. Кратко: MRI не выполняет одновременно более одного рубишного кода. Как только в поток заходит в C-extension или в IO операцию — MRI передает управление другому потоку.
Вот тут и проявляется параллельность.
Поэтому если в приложении медленный IO, то потоки в MRI имеют смысл.
Отдельный инстанс не создается, создается отдельный поток.
Настоящие треды нужны, если много ruby-кода. Если же большую часть поток занят внешними операциями (io, сеть) то сойдут и MRI зеленые потоки.
Другими словами, Вы пытаетесь вывернуться, и сами себе противоречите:
Выше Вы писали:
я разъяснил Вам ваше заблуждение — нагрузка может распределятся на разные ядра, это очень важная деталь, без которой MRI потоки (а тем более что они реализованы через native threads) теряют смысл.
Т.е. Вы же не будете отрицать, что в ~99% случаев web-приложениях используются внешние данные — запросы к БД, внешним источникам (IO операции) и тп? Причем, чаще всего эти операции выполняются дольше чем ruby-код. Именно здесь и идет выигрыш, и задействуются дополнительные ядра.
Да и с чего Вы взяли что в приложениях не применяются C-extensions наподобие nokogiri? JSON-parser/encoder'ы? посмотрите Yajl например. Но больше обратите внимание на IO операции.
Давайте разберемся с самого начала:
1. В MRI 1.9 применяются нативные threads. Каждый раз когда создается экземпляр класса Thread — создается нативный thread OS.
2. При выполнении ruby кода (или C-кода внутри ruby) блокируется GIL. Чтобы выполнялся только один thread.
3. IO операции: операции с файлами, сетевые операции — действительно блокируемые.
4. Но до входа в IO операции освобождается GIL (или как Вы называете флаг прерывания), благодаря этому спящие потоки получают управление.
5. Кастомные C-extensions (nokogiri, json parser, etc) которые напрямую не работают с структурами MRI также освобождают GIL
6. В EM совсем другой принцип — есть всего один поток, но все (в идеале) IO операции неблокируемые.
7. EM использует паттерн Reactor — используются средства OS (epoll,select,etc) для опроса дескрипторов, готовых для чтения/записи.
8. В этом случае ruby код должен быть как можно более быстрым, чтобы быстрей вернуть управление реактору.
9. В EM есть еще thread pools, но мы их не рассматриваем, т.к. являются workaround для блокируемых операций (типа клиента mysql).
Ваши заблуждения:
1. C-код (C-extendsions) который не работает с MRI структурами — может освобождать GIL и будет задействовано более одного ядра.
2. EM переключает не на следующего желающего — а на тот блок кода (callback), для дескриптора которого OS сообщает, что готовы данные для чтения, или запись завершена и тп.
Т.к. C-код как правило выполняется достаточно быстро — профит получается небольшой.
Вот ссылки для дальнейшего чтения:
merbist.com/2011/02/22/concurrency-in-ruby-explained/
stackoverflow.com/questions/1203565/native-threads-in-ruby-1-9-1-whats-in-it-for-me
yehudakatz.com/2010/08/14/threads-in-ruby-enough-already/
www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/
Процессы тут совершенно ни причем, и мы не рассматриваем их.
Если вернуться к первоначальному вопросу — то sinatra+em и rails+threads разные инструменты, которые нельзя сравнивать напрямую, именно поэтому он у меня и возник, т.к. Вы не озвучили, что имеете в виду именно EM.
Какая eventmachine может быть, если sinatra запущена, например из под passenger?
Я использую в нагруженном проекте async_sinatra + em + fibers + thin и знаю о чем говорю.
Вот тут и проявляется параллельность.
Поэтому если в приложении медленный IO, то потоки в MRI имеют смысл.
Настоящие треды нужны, если много ruby-кода. Если же большую часть поток занят внешними операциями (io, сеть) то сойдут и MRI зеленые потоки.