2013-10-03 12 views
5

Ich bin nicht sicher, dass diese Frage nur mit Ruby verwandt ist, vielleicht finden Sie es relevant für jede andere Sprache.Leistung: Ruby CSV.foreach vs CSV.parse

Ich frage mich, ob ich Parse oder foreach verwenden sollte:

  • CSV.parse(filepath) wird die gesamte Datei analysieren und ein Array von Arrays, die die CSV-Datei reflektieren und im Speicher gespeichert werden. Später werde ich dieses Array Zeilen verarbeiten.

  • CSV.foreach(filepath) liest/analysiert die Datei Zeile für Zeile und verarbeitet sie Zeile für Zeile.

Wenn es um die Leistung geht, gibt es einen Unterschied? Gibt es einen bevorzugten Ansatz?

PS: Ich weiß, dass ich in Ruby einen Block mit der Parse-Methode bereitstellen kann und dann wird es jede Zeile getrennt behandeln.

+1

Leistungsunterschied? Das hängt wahrscheinlich davon ab, wie groß Ihre CSV-Dateien sind und wie Sie mit ihnen arbeiten. Sie können diese Frage einfach selbst beantworten, indem Sie vergleichen, wie Sie die Dinge in Ihrer Situation verwenden würden. –

+0

Hallo @muistooshort, danke für deine Antwort. Ich habe Ihre Antwort erhalten, und ich werde einfach messen, wie schnell das Parsen ist und wie beschäftigt mein Speicher und CPU während des Prozesses ist. Im Allgemeinen sollten normalerweise sehr große Dateien Zeile für Zeile verarbeitet werden, und wenn die Datei hell genug ist, kann sie in den Speicher geladen werden, richtig? – benams

+1

Normalerweise nehme ich an. Es hängt davon ab, welcher Stil für das, was Sie tun, sinnvoll ist. –

Antwort

5

Hier ist mein Test:

require 'csv' 
require 'benchmark' 

small_csv_file = "test_data_small_50k.csv" 
large_csv_file = "test_data_large_20m.csv" 

Benchmark.bmbm do |x| 
    x.report("Small: CSV #parse") do 
     CSV.parse(File.open(small_csv_file), headers: true) do |row| 
      row 
     end 
    end 

    x.report("Small: CSV #foreach") do 
     CSV.foreach(small_csv_file, headers: true) do |row| 
      row 
     end 
    end 

    x.report("Large: CSV #parse") do 
     CSV.parse(File.open(large_csv_file), headers: true) do |row| 
      row 
     end 
    end 

    x.report("Large: CSV #foreach") do 
     CSV.foreach(large_csv_file, headers: true) do |row| 
      row 
     end 
    end 
end 

Rehearsal ------------------------------------------------------- 
Small: CSV #parse  0.950000 0.000000 0.950000 ( 0.952493) 
Small: CSV #foreach 0.950000 0.000000 0.950000 ( 0.953514) 
Large: CSV #parse 659.000000 2.120000 661.120000 (661.280070) 
Large: CSV #foreach 648.240000 1.800000 650.040000 (650.062963) 
------------------------------------------- total: 1313.060000sec 

          user  system  total  real 
Small: CSV #parse  1.000000 0.000000 1.000000 ( 1.143246) 
Small: CSV #foreach 0.990000 0.000000 0.990000 ( 0.984285) 
Large: CSV #parse 646.380000 1.890000 648.270000 (648.286247) 
Large: CSV #foreach 651.010000 1.840000 652.850000 (652.874320) 

Die Benchmarks mit 8 GB Speicher auf einem Macbook Pro laufen gelassen wurden. Die Ergebnisse zeigen an, dass die Leistung statistisch äquivalent ist, entweder mit CSV # parse oder CSV # foreach.

Headers Optionen entfernt (nur kleine Datei getestet):

require 'csv' 
require 'benchmark' 

small_csv_file = "test_data_small_50k.csv" 

Benchmark.bmbm do |x| 
    x.report("Small: CSV #parse") do 
     CSV.parse(File.open(small_csv_file)) do |row| 
      row 
     end 
    end 

    x.report("Small: CSV #foreach") do 
     CSV.foreach(small_csv_file) do |row| 
      row 
     end 
    end 
end 

Rehearsal ------------------------------------------------------- 
Small: CSV #parse  0.590000 0.010000 0.600000 ( 0.597775) 
Small: CSV #foreach 0.620000 0.000000 0.620000 ( 0.621950) 
---------------------------------------------- total: 1.220000sec 

          user  system  total  real 
Small: CSV #parse  0.590000 0.000000 0.590000 ( 0.597594) 
Small: CSV #foreach 0.610000 0.000000 0.610000 ( 0.604537) 

Hinweise:

large_csv_file war von einer anderen Struktur als small_csv_file und damit Ergebnisse (dh Zeilen/s) zwischen den beiden Dateien vergleichen würde ungenau sein.

small_csv_file hatte 50.000 Aufzeichnungen

large_csv_file hatte 1.000.000 Datensätze

Headers Option auf true gesetzt Leistung für jedes Feld in der Reihe für den Aufbau einer Hash signifikant aufgrund reduziert (der HeadersConverters siehe Abschnitt: http://www.ruby-doc.org/stdlib-2.0.0/libdoc/csv/rdoc/CSV.html)

+0

Ich bezweifle die Frage ist so viel über CPU-Nutzung und Zeit, wie es Speicherverbrauch ist. Wenn Sie für jede Zeile eine Aktion ausführen, ist nur die Zeile im Speicher konservativ. Wenn Sie ein Array von Arrays erhalten, sollte die Speichernutzung gleich sein. –