2016-06-17 1 views
1

Je fais face à une grande quantité de données et je m'inquiète de l'efficacité de mes opérations à l'échelle. Après l'analyse comparative, le délai moyen d'exécution de cette chaîne de code est d'environ 0,004 seconde. Le but de cette ligne de code est de trouver la différence entre les deux valeurs dans chaque emplacement de tableau. Dans une opération précédente, 111.111 a été chargé dans les tableaux dans des emplacements contenant des données non valides. En raison de problèmes de domaine temporel étranges, je devais le faire parce que je ne pouvais pas simplement supprimer les valeurs et j'avais besoin d'un espace réservé distinct. Je pourrais probablement utiliser «nul» ici à la place. Quoi qu'il en soit, revenons à l'explication. Cette ligne de code vérifie que ni le tableau n'a cet espace réservé 111.111 dans l'emplacement actuel. Si les valeurs sont valides, alors j'effectue l'opération mathématique, sinon je veux supprimer les valeurs (ou au moins les exclure du nouveau tableau dans lequel j'écris). J'ai accompli ceci en plaçant un «néant» à cet endroit et en compactant ensuite la rangée après.Ruby: Augmenter l'efficacité

Le temps de 0.004sec pour 4000 points de données dans chaque tableau n'est pas terrible mais cette ligne de code est exécutée 25M fois. J'espère que quelqu'un pourrait être en mesure d'offrir un aperçu de la façon dont je pourrais optimiser cette ligne de code.

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' n'est absolument pas nécessaire ici. –

+0

Et oui, 4000% d'amélioration de la création de 5000 threads - c'est de la fantaisie :) –

+0

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

Répondre

0

Vous pouvez essayer dans la déclaration ternaire parallel joyau https://github.com/grosser/parallel et l'exécuter sur plusieurs threads

+0

Ah, c'est vraiment un bijou très utile, mais il ne semble pas être pris en charge sur ruby 2.3.0p0 (2015-12-25 révision 53290) [x64-mingw32]. –

+0

@ srm985 C'est dommage – Ruslan

+0

L'exécution de plusieurs threads n'entraînera pas forcément une accélération, et pourrait même les ralentir, en particulier lorsque trop de threads sont utilisés. Il y a un bon équilibre et les tests le trouveront. –

2

Vous gaspillez CPU générer nil, puis en utilisant compact pour les supprimer. Au lieu de cela, utilisez reject ou select pour trouver les éléments ne contenant pas 111.111 puis map ou quelque chose de similaire.

Au lieu de:

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] 

Je commence par:

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] 

Ou:

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] 

Analyse comparative des tableaux de différentes tailles montre de bonnes choses à savoir:

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) 

Ajustez la taille de DECIMAL_SHIFT et DATA_ARRAY et l'emplacement de 111.111 et voyez ce qui se passe pour avoir une idée des expressions qui fonctionnent le mieux pour la taille et la structure de vos données et affinez le code si nécessaire.

+0

L'utilisation de 'nil' et de 'compact' a donné un temps d'exécution de 0,000867sec alors que l'utilisation de 'reject' a donné un temps d'exécution de 0,001219sec. Ceux-ci ont été exécutés sur des tableaux d'environ 4000 points. –

+0

Benchmarking résultats que faible me rendent suspect. Sans données d'échantillon utilisables et le code de référence nous ne pouvons pas vraiment comparer les pommes aux pommes. –

+0

Je l'ai également couru pour 2000 itérations et ai comparé la boucle complète. Les résultats étaient respectivement de 8,922337sec et 10,834802sec. Je comprends que c'est un peu compliqué sans que je fournisse des données d'échantillon. J'apprécie toute l'aide à ce sujet. –