2016-06-17 4 views
1

Я имею дело с большим количеством данных, и меня беспокоит эффективность моих операций в масштабе. После бенчмаркинга среднее время выполнения этой строки кода составляет около 0,004 сек. Цель этой строки кода - найти разницу между двумя значениями в каждом местоположении массива. В предыдущей операции 111.111 был загружен в массивы в местах, содержащих недопустимые данные. Из-за некоторых странных вопросов во временном домене мне нужно было это сделать, потому что я не мог просто удалить значения, и мне нужен был какой-то отличимый заполнитель. Вместо этого я мог бы использовать здесь «ноль». В любом случае, вернемся к объяснению. Эта строка кода проверяет, чтобы ни один массив не имел этот 111.111 placeholder в текущем местоположении. Если значения действительны, я выполняю математическую операцию, иначе я хочу удалить значения (или, по крайней мере, исключить их из нового массива, к которому я пишу). Я выполнил это по месту «нуль» в этом месте, а затем впоследствии уплотнил массив.Ruby: Повышение эффективности

Время 0,004 секунды для 4000 точек данных в каждом массиве не страшно, но эта строка кода выполняется 25M раз. Я надеюсь, что кто-то сможет предложить некоторое представление о том, как я могу оптимизировать эту строку кода.

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' здесь совершенно не нужен. –

+0

И да, 4000% улучшение от создания 5000 потоков - это фантазия :) –

+0

Без почтового индекса: http://pastie.org/10881223 –

ответ

0

Вы можете попробовать parallel камень https://github.com/grosser/parallel и запустить его на несколько потоков

+0

А это, безусловно, очень полезный внешний вид, но он, похоже, не поддерживается ruby 2.3.0p0 (версия 2015-12-25 версия 53290) [x64-mingw32]. –

+0

@ srm985 Это позор – Ruslan

+0

Запуск в нескольких потоках не обязательно ускорит работу, и на самом деле может замедлить их работу, особенно когда используется слишком много потоков. Там счастливый баланс, и тестирование найдет его. –

2

Вы расточительствуя процессор, генерирующий nil в тройном заявлении, затем с помощью compact, чтобы удалить их. Вместо этого используйте reject или select, чтобы найти элементы, не содержащие 111.111, затем map или что-то подобное.

Вместо:

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] 

Я хотел бы начать с:

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] 

Или:

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] 

Бенчмаркинг массивы различного размера показывает хорошие вещи, чтобы знать:

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) 

Отрегулируйте размер DECIMAL_SHIFT и DATA_ARRAY и разместите 111.111 и посмотрите, что получится, чтобы понять, какие выражения лучше всего подходят для вашего размера и структуры данных, и при необходимости уточнить код.

+0

Использование 'nil' и 'compact' дало время выполнения 0,000867 секунд при использовании 'reject', давало время выполнения 0.001219 сек. Они выполнялись на массивах около 4000 точек. –

+0

Результаты бенчмаркинга, которые заставляют меня подозревать. Без использования данных образца и эталонного кода мы не можем сравнивать яблоки с яблоками. –

+0

Я также запускал его для 2000 итераций и сравнивал полный цикл. Результаты были 8.922337 сек и 10.834802 сек. Соответственно. Я понимаю, что это немного сложно, если я не предоставил образцы данных. Я действительно ценю всю помощь в этом. –

Смежные вопросы