在Sinatra中缓存文本文件内容

时间:2012-05-23 20:53:39

标签: ruby caching sinatra

我是Sinatra的新手和网络编程,所以使用的一些术语可能不太对。总之...

我有一个应用程序,逐行读取.txt数组,然后当你加载index.html.erb时,它会随机显示其中一行。我把内容放在一个文本文件而不是直接放入一个数组,这样如果我需要添加更多的数据,它就更容易更新,然后直接添加到数组并重新部署应用程序。我担心的是,如果它正在重新创建数组并在每次加载页面时重新读取文件。我不确切知道服务器端的工作方式是什么,或者如何检查它。创建数组的代码为:

before do
  @ways ||= ['']
  if @ways[1].nil?
    File.open('ways.txt', 'r').each_line { |line| @ways << line }
  end
end

然后我的路线:

get '/' do
  @way = @ways.sample

  erb :index
end

有没有办法确保尽可能高效?还是应该完全以其他方式完成?根据Chrome Dev工具,它每页传输大约800b。

1 个答案:

答案 0 :(得分:4)

你在这里写的内容确实会在每个请求中将文件读入一个数组。

提示:您可以使用@ways = File.readlines('ways.txt')

缩短速度

如果你想缓存这个数组,你可以在app启动时作为常量,例如:

WAYS = File.readlines('ways.txt').map(&:chomp)
get "/" do
  @way = WAYS.sample
  erb :index
end

但是,如果您编辑了文本文件,则需要退出并重新启动服务器。如果您想避免这种情况,可以在before操作中检查文件的修改时间,如果内容已更改,则只更新数组(replace)。

如果您需要有关此最后建议的帮助,请告诉我,我可以编辑以适应。


编辑:这是使用常量来保存数据并仅在文件更改时重新加载的一种方法:

WAYS = { file:'ways.txt', all:[] }
before do
  if WAYS[:updated] != (mtime=File.mtime(WAYS[:file]))
    WAYS[:all].replace File.readlines(WAYS[:file]).map(&:chomp)
    WAYS[:updated] = mtime
  end
end
get "/" do
  @way = WAYS[:all].sample
  erb :index
end

这有点激进 - 检查每个请求的文件修改时间 - 但除了最重的负载或最慢的磁盘之外,性能应该没问题。

另一种解决方案是启动一个线程,每隔几分钟强制检查/更新一次阵列,例如

require 'sinatra'

WAYS = { file:'ways.txt', all:[] }
Thread.new do
  loop do
    if WAYS[:updated] != (mtime= File.mtime(WAYS[:file]))
      WAYS[:all].replace File.readlines(WAYS[:file]).map(&:chomp)
      WAYS[:updated] = mtime
    end
    sleep 5 # seconds
  end
end

get '/' do
  WAYS[:all].sample
end