2012-01-13 2 views
3

В проекте Ruby, который я провел некоторое время в последнее время, я подсчитываю пересечение двух больших наборов строк.Почему сравнение строк так быстро по сравнению с целым сравнением?

Из того, что, как я думал, я понял, я решил, что было бы очень полезно сравнивать целые числа вместо строк (все эти строки хранятся в базе данных, и я мог бы просто просто заменить их на идентификаторы)

Когда я на самом деле сделал бенчмаркинг, я закончил поиск полной противоположности.

Сначала я генерироваться наборы 850 строк, и наборы ~ 850 больших целых чисел:

r = Random.new 
w1 = (1..850).collect{|i| w="";(0..3).collect{|j| (rand*26 + 10).to_i.to_s(35)}.each{|l| w+=(l.to_s)};w}.to_set 
w2 = (1..850).collect{|i| w="";(0..3).collect{|j| (rand*26 + 10).to_i.to_s(35)}.each{|l| w+=(l.to_s)};w}.to_set 

i1 = (1..2000).collect{|i| (r.rand*1000).to_i**2}.to_set; 
i2 = (1..2000).collect{|i| (r.rand*1000).to_i**2}.to_set; 

И тогда я приуроченная сравнений:

t=Time.now;(0..1000).each {|i| w1 & w2};Time.now-t 
=> 0.301727 
t=Time.now;(0..1000).each {|i| i1 & i2};Time.now-t 
=> 0.70151 

Что я думал, что сошел с ума! Я всегда считал, что целочисленное сравнение было намного быстрее.

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

ответ

7

Скорость работы множества пересечений по-видимому, зависит от количества пересекающихся элементов.

Ваш целый код создания создает значительно большее количество пересекающихся элементов, возможно, потому, что он выбирает 2000 записей из меньшего набора (1000).

В одном тесте, например, 755 из 857 записей в i1 дублировались в i2, но только 2 из 849 записей в w1 были дублированы в w2.

Когда я побежал простую переделку:

755.times {|x| w2 << w1.to_a[x]} 

(демпинг 755 элементов в w2, которые, как известны, в w1), результаты на моей системе показали операцию строки набора, чтобы быть гораздо ближе к эквиваленту целочисленная операция.

Мои первоначальные результаты были:

1.9.2p180 :006 > t=Time.now;(0..1000).each {|i| w1 & w2};Time.now-t 
=> 1.020355 
1.9.2p180 :007 > t=Time.now;(0..1000).each {|i| i1 & i2};Time.now-t 
=> 2.057535 

Мои результаты после создания двух наборов множеств более, так в терминах пересекающихся элементов, с помощью:

1.9.2p180 :051 > 755.times {|x| w2 << w1.to_a[x]} 
1.9.2p180 :052 > w2 = w2.to_a[-849..-1].to_set 

были:

1.9.2p180 :053 > t=Time.now;(0..1000).each {|i| w1 & w2};Time.now-t 
=> 2.014967 
1.9.2p180 :054 > t=Time.now;(0..1000).each {|i| i1 & i2};Time.now-t 
=> 2.037542 
1.9.2p180 :055 > [i1.length, i2.length, w1.length, w2.length, (i1 & i2).length, (w1 & w2).length] 
=> [857, 884, 849, 849, 755, 754] 

Надеюсь, это поможет некоторым; два тайминга находятся в пределах того, что я считаю ошибкой, что другие вещи в системе могут вызвать разницу. Они, по существу, равны для строк этой длины.

+0

Отличный ответ. Хорошо написанный и описательный. Спасибо за помощь. :] – BananaNeil

1

Целочисленные сравнения все еще самые быстрые.
проверить эту ссылку:

3

Причина в том, что это медленнее, потому что вы не получаете столько совпадающих предметов. Требуется время, чтобы создать новый массив пересечения, а не фактическое совпадение.

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