我一直在读取来自csv的数据,如果有一个大的csv文件,为了避免这个超时(机架12秒超时)我只读了25行之后来自csv的25行它再次发出请求所以这将继续,直到读完所有行。
def read_csv(offset)
r_count = 1
CSV.foreach(file.tempfile, options) do |row|
if r_count > offset.to_i
#process
end
r_count += 1
end
但是这里它正在创建一个新问题,让我们首先读取25行,然后当下一个请求偏移时为25,那时它将读取前25行,然后它将从26开始读取并进行处理,那怎么能我跳过已经读过的行?,我试过这个如果下一个跳过迭代但是失败了,还是有其他有效的方法可以做到这一点?
答案 0 :(得分:0)
<强>代码强>
Error (active)
function "scalePoint" (declared at line 13) was previously not declared constexpr
纯Ruby - SLOWER
def read_csv(fileName)
lines = (`wc -l #{fileName}`).to_i + 1
lines_processed = 0
open(fileName) do |csv|
csv.each_line do |line|
#process
lines_processed += 1
end
end
end
<强>基准强>
我运行了一个新的基准,比较了您提供的原始方法和我自己的方法。我还包括了测试文件信息。
def read_csv(fileName)
lines = open("sample.csv").count
lines_processed = 0
open(fileName) do |csv|
csv.each_line do |line|
#process
lines_processed += 1
end
end
end
<强>解释强>
注意:我添加了一个纯ruby方法,因为使用"File Information"
Lines: 1172319
Size: 126M
"django's original method"
Time: 18.58 secs
Memory: 0.45 MB
"OneNeptune's method"
Time: 0.58 secs
Memory: 2.18 MB
"Pure Ruby method"
Time: 0.96
Memory: 2.06 MB
有点作弊,而且不可移植。在大多数情况下,使用纯语言解决方案非常重要。
您可以使用此方法处理非常大的CSV文件。
~2MB内存我觉得考虑到文件大小是非常优化的,它有点增加了内存使用量,但节省的时间似乎是一个公平的交易,这将防止超时。
我确实修改了采用fileName的方法,但这只是因为我测试了许多不同的CSV文件以确保它们都能正常工作。如果您愿意,可以删除它,但它可能会有所帮助。
我还删除了偏移的概念,因为您声明最初包含它以尝试自己优化解析,但这不再是必需的。
此外,我会跟踪文件中有多少行,以及自您需要使用该信息以来处理了多少行。注意,这些行只适用于基于unix的系统,并且它是一个避免将整个文件加载到内存中的技巧,它计算新行,并且我为最后一行添加1。如果您不打算将标题计为行,则可以删除+1并将行更改为“行”以更准确。
您可能遇到的另一个后勤问题是,如果CSV文件有标题,需要弄清楚如何处理。
答案 1 :(得分:-2)
你可以使用延迟读取来加快速度,整个文件都不会被读取,只是从文件的开头直到你使用的块。 有关示例,请参阅http://engineering.continuity.net/csv-tricks/和https://reinteractive.com/posts/154-improving-csv-processing-code-with-laziness。
您还可以使用SmarterCSV来处理这样的块。
SmarterCSV.process(file_path, {:chunk_size => 1000}) do |chunk|
chunk.each do |row|
# Do your processing
end
do_something_else
end
enter code here
我这样做的方法是将结果传输给用户,如果你看到发生了什么事,那就不必费心了。你提到的超时不会发生在这里。 我不是Rails用户,所以我举一个Sinatra的例子,这也可以用Rails完成。参见例如http://api.rubyonrails.org/classes/ActionController/Streaming.html
require 'sinatra'
get '/' do
line = 0
stream :keep_open do |out|
1.upto(100) do |line| # this would be your CSV file opened
out << "processing line #{line}<br>"
# process line
sleep 1 # for simulating the delay
end
end
end
更好但有点复杂的解决方案是使用websockets,一旦处理完成,浏览器就会从服务器接收结果。您还需要在客户端中使用一些javascript来处理这个问题。见https://github.com/websocket-rails/websocket-rails