2016-06-17 13 views
1

Ich habe es mit einer großen Menge von Daten zu tun, und ich mache mir Sorgen über die Effizienz meiner Operationen im Maßstab. Nach dem Benchmarking beträgt die durchschnittliche Ausführungszeit für diesen Code ca. 0,004 Sekunden. Das Ziel dieser Codezeile besteht darin, den Unterschied zwischen den beiden Werten in jeder Array-Position zu finden. In einer vorherigen Operation wurde 111.111 in die Arrays an Orten geladen, die ungültige Daten enthielten. Aufgrund einiger seltsamer Zeitdomänenprobleme musste ich dies tun, da ich die Werte nicht einfach entfernen konnte und einen unterscheidbaren Platzhalter benötigte. Ich könnte wahrscheinlich stattdessen 'Nil' hier verwenden. Wie auch immer, zurück zur Erklärung. Diese Codezeile prüft, ob keines der Arrays diesen 111.111-Platzhalter am aktuellen Speicherort besitzt. Wenn die Werte gültig sind, führe ich die mathematische Operation aus, ansonsten möchte ich die Werte löschen (oder sie zumindest aus dem neuen Array ausschließen, in das ich schreibe). Ich habe dies erreicht, indem ich an dieser Stelle einen Nullpunkt platziert habe und das Array anschließend komprimiert habe.Ruby: Steigerung der Effizienz

Die Zeit von 0,004 Sekunden für 4000 Datenpunkte in jedem Array ist nicht schrecklich, aber diese Codezeile wird 25M mal ausgeführt. Ich hoffe, dass jemand einen Einblick geben könnte, wie ich diese Codezeile optimieren könnte.

temp_row = row_1.zip(row_2).map do |x, y| 
    x == 111.111 || y == 111.111 ? nil : (x - y).abs 
end.compact 
+0

'zip' wird hier nicht benötigt. –

+0

Und ja, 4000% Verbesserung durch das Erstellen von 5000 Threads - das ist Fantasie :) –

+0

Ohne zip: http://pastie.org/10881223 –

Antwort

0

können Sie versuchen, die parallel gem https://github.com/grosser/parallel und es auf mehrere Threads laufen

+0

Ah, das ist definitiv ein sehr nützlich aussehendes Juwel, aber es scheint nicht unterstützt zu werden Ruby 2.3.0p0 (2015-12-25 Revision 53290) [x64-mingw32]. –

+0

@ srm985 Das ist eine Schande – Ruslan

+0

Laufen in mehreren Threads wird nicht notwendigerweise beschleunigen, und könnte sie tatsächlich verlangsamen, besonders wenn zu viele Threads verwendet werden. Es gibt eine glückliche Balance und das Testen wird es finden. –

2

Sie verschwenden CPU nil in dem ternären Anweisung zu erzeugen, dann compact, sie zu entfernen. Verwenden Sie stattdessen reject oder select, um Elemente zu finden, die nicht 111.111, dann map oder etwas Ähnliches enthalten.

Statt:

row_1 = [1, 111.111, 2] 
row_2 = [2, 111.111, 4] 

temp_row = row_1.zip(row_2).map do |x, y| 
    x == 111.111 || y == 111.111 ? nil : (x - y).abs 
end.compact 
temp_row # => [1, 2] 

würde ich beginnen mit:

temp_row = row_1.zip(row_2) 
       .reject{ |x,y| x == 111.111 || y == 111.111 } 
       .map{ |x,y| (x - y).abs } 
temp_row # => [1, 2] 

Oder:

temp_row = row_1.zip(row_2) 
       .each_with_object([]) { |(x,y), ary| 
        ary << (x - y).abs unless (x == 111.111 || y == 111.111) 
       } 
temp_row # => [1, 2] 

Benchmarking unterschiedlicher Größe Arrays gute Dinge zeigt wissen:

require 'benchmark' 

DECIMAL_SHIFT = 100 
DATA_ARRAY = (1 .. 1000).to_a 
ROW_1 = (DATA_ARRAY + [111.111]).shuffle 
ROW_2 = (DATA_ARRAY.map{ |i| i * 2 } + [111.111]).shuffle 

Benchmark.bm(16) do |b| 
    b.report('ternary:') do 
    DECIMAL_SHIFT.times do 
     ROW_1.zip(ROW_2).map do |x, y| 
     x == 111.111 || y == 111.111 ? nil : (x - y).abs 
     end.compact 
    end 
    end 

    b.report('reject:') do 
    DECIMAL_SHIFT.times do 
     ROW_1.zip(ROW_2).reject{ |x,y| x == 111.111 || y == 111.111 }.map{ |x,y| (x - y).abs } 
    end 
    end 

    b.report('each_with_index:') do 
    DECIMAL_SHIFT.times do 
     ROW_1.zip(ROW_2) 
      .each_with_object([]) { |(x,y), ary| 
      ary += [(x - y).abs] unless (x == 111.111 || y == 111.111) 
      } 
    end 
    end 
end 

# >>      user  system  total  real 
# >> ternary:   0.240000 0.000000 0.240000 ( 0.244476) 
# >> reject:   0.060000 0.000000 0.060000 ( 0.058842) 
# >> each_with_index: 0.350000 0.000000 0.350000 ( 0.349363) 

Passen Sie die Größe DECIMAL_SHIFT und DATA_ARRAY und die Platzierung von 111.111 und sehen, was passiert, um eine Vorstellung davon zu bekommen, welche Ausdrücke für Ihre Datengröße und Struktur am besten funktionieren und den Code nach Bedarf optimieren.

+0

Die Verwendung von 'nil' und 'compact' ergab eine Ausführungszeit von 0,000867 s, während die Verwendung von 'reject' eine Ausführungszeit von 0,001219 s ergab. Diese wurden auf Arrays von etwa 4000 Punkten ausgeführt. –

+0

Benchmarking-Ergebnisse, die niedrig sind, machen mich misstrauisch. Ohne brauchbare Beispieldaten und den Benchmark-Code können wir Äpfel nicht wirklich mit Äpfeln vergleichen. –

+0

Ich lief es auch für 2000 Iterationen und benchmarkierte die volle Schleife. Die Ergebnisse waren 8.922337sec bzw. 10.834802sec. Ich verstehe, dass es ein bisschen schwierig ist, ohne Beispieldaten zur Verfügung zu stellen. Ich schätze jedoch all die Hilfe dazu. –