#ruby-on-rails #ruby #ruby-on-rails-3 #memoization
#ruby-on-rails #ruby #ruby-on-rails-3 #запоминание
Вопрос:
Например, следующий код:
class FoosController < ApplicationController
def index
if !@foo.nil?
render :locals => {:bar => @foo}
return
else
@foo = rand 10
render :locals => {:bar => @foo}
end
end
end
если я загружу localhost:3000/foos
несколько раз, он будет показывать разные значения, и неудивительно, что это режим разработки, потому что Rails перезагружает контроллер (а также модель и представление) каждый раз, когда поступает запрос браузера.
Но даже в рабочем режиме, когда все загружено и остается там, @foo
значение s не будет сохраняться в запросах браузера? Каждый раз при перезагрузке страницы в веб-браузере отображается другое число. Значит, Rails будет каждый раз очищать все значения? Есть ли способ кэшировать или «запоминать» результаты по запросам, если мы не используем СУБД?
Удивительно, но я только что попробовал использовать переменную класса, и в режиме разработки она каждый раз выдает другое число. В рабочем режиме число остается неизменным в Firefox, и тогда Chrome также будет показывать это число все время, пока сервер не будет перезапущен:
class FoosController < ApplicationController
@@foo = nil
def index
if !@@foo.nil?
render :locals => {:bar => @@foo}
return
else
@@foo = rand 10
render :locals => {:bar => @@foo}
end
end
end
Почему переменная класса может запоминаться, а переменная экземпляра — нет? Является ли использование переменной класса надежным способом надежно «запоминать вещи» по запросу в Rails 2.x, 3.x и Ruby 1.8.7 и 1.9.2?
Ответ №1:
Это преднамеренное и желаемое поведение, каждый запрос создает экземпляр нового экземпляра контроллера, так что у запроса не возникает проблем с остатками предыдущих запросов.
Возможно, вы захотите использовать session
или flash
хэши для хранения @foo
между запросами.
class FoosController < ApplicationController
def index
@foo = session[:foo] ||= rand(10)
render :locals => {:bar => @foo}
end
end
session[:foo]
будет сохраняться на протяжении всего пути, но вы можете использовать flash[:foo]
, если хотите сохранить его только в одном запросе.
Комментарии:
1. Обратите внимание, что сеанс по умолчанию сохраняется в файлах cookie, которые хранятся на компьютере пользователя (не помещайте туда конфиденциальные данные), и имеют ограниченный размер файла (что-то вроде 2 или 4 Кб). Кроме того, у каждого пользователя есть уникальный сеанс, поэтому кэширование будет осуществляться для данного пользователя, но не для всех пользователей.
Ответ №2:
@@foo
обозначает переменную класса, @foo
переменную экземпляра. При каждом запросе создается новый экземпляр контроллера. А для кэширования я действительно рекомендую memcache или что-то подобное (из-за разветвленной природы производственных серверов rails).
Ответ №3:
Даже если вы изменяете настройки так, как предлагает edgerunner, в рабочей среде у вас может быть запущено несколько экземпляров mongrel или thin, и каждый из этих контроллеров будет иметь разные переменные flash, и текущий подход не будет работать. Продолжайте с тем, что говорит Tass, что-то вроде memcache или redis для сохранения таких данных в памяти.
Комментарии:
1. Kunday по умолчанию
session
иflash
сохраняются в файлах cookie, поэтому несколько экземпляров не будут проблемой. Другими вариантами хранения сеанса являются Memcached и database, которые также позволяют избежать проблемы с несколькими экземплярами. Фактически, единственный упомянутый здесь подход, который потерпит неудачу в нескольких экземплярах, — это подход с переменной класса в исходном вопросе.2. Спасибо, что исправил меня, Edgerunner. Но сохранение в сеансе [:foo] ограничено одним браузером, верно? Я предполагаю, что хранение в Memcache или базе данных будет осуществляться в нескольких браузерах, и если алгоритм сложный (вычисление для каждого уникального сеанса браузера по-прежнему дорого, верно?), я думаю, нам все равно следует использовать какой-нибудь memcached или database, верно? Поправьте меня, если я ошибаюсь.
3. Я бы предположил, что если вы хотите сохранить что-то в запросах, в большинстве случаев это последовательные запросы одного пользователя. Хранилище файлов cookie, подходящее для такого сценария. Однако, если вы хотите что-то накопительное, вам, вероятно, следует сохранить в базе данных. Memcached быстр, постоянен и хорош, но даже он не является действительно постоянным. А memcached обходится дорого, если вы хотите сохранить много данных. В любом случае фактический выбор имеет несколько параметров, подлежащих анализу. На это трудно дать окончательный ответ.
4. Согласовано. Я никогда не сталкивался со сценарием, в котором был бы эквивалентный тестовый пример. Раньше у меня была некоторая работа, которая требовала таких вещей. Надеюсь, что работа над этим даст некоторое представление. Между memcached прав ли локальный сервер, сообщая о его дороговизне, вы упоминаете стоимость memcached heroku?
5. Memcached — это непостоянное хранилище в памяти, и каждый байт памяти всегда дороже, чем каждый байт диска. Memcached не гарантирует надежного сохранения каких-либо данных. При перезапуске сервера произойдет сбой. Как следует из названия, это хранилище кэша, которое помогает ускорить процесс. Это не постоянное хранилище.