Исходный 'rcs' инструмент все еще там и все еще работает (над Unix и окнами/DOS) и является возможно самым простым из этих инструментов, который является, почему я рекомендовал бы его для работы в команде с двумя людьми в той же системе (например, том же офисе, том же файловом сервере или хосте Unix). Только стоит войти в клиент-серверную модель как подрывная деятельность, если Вы работаете в отдельных средах.
Я обнаружил, что эталонная реализация Ruby (ну, Ruby) (не научно сказано) работает очень медленно.
Если у вас есть возможность, попробуйте запустить вашу программу под JRuby! Чарльз Наттер и другие люди из Sun утверждают, что значительно ускорили Руби.
Я, например, был бы больше всего заинтересован в ваших результатах.
Это могло быть потому, что диктовки в Python намного быстрее, чем хэши в Ruby
Я только что провел быстрый тест, построив хэш из 12345678 элемента в Ruby1.8.7 занял 3 раза больше, чем пока Python. Ruby1.9 был примерно вдвое длиннее Python.
Вот как я тестировал
python
$ time python -c "d={}
for i in xrange(12345678):d[i]=1"
ruby
$ time ruby -e "d={};12345678.times{|i|d[i]=1}"
Однако этого недостаточно, чтобы учесть ваше несоответствие.
Возможно, стоит поискать ввод-вывод файлов в - закомментируйте весь хэш-код и посмотрите, сколько времени потребуется пустым циклам для обработки файлов.
Вот еще одна версия на Python с использованием defaultdict и менеджеров контекста
from collections import defaultdict
hashes = defaultdict(int)
with open('c:\\file1.txt', 'r') as f:
for line in f:
hashes[line] += 1
print "Done file 1"
with open('c:\\file2.txt', 'r') as f:
for line in f:
if line in hashes:
hashes[line] -= 1
else:
print "Hash not found!"
print "Done file 2"
num_errors = 0
for key,value in hashes.items(): # hashes.iteritems() might be better here
if value != 0:
print "Uneven hash count: %s" % key
num_errors += 1
print "Total of %d mismatches found" % num_errors
На стороне Python вы можете перебирать элементы словаря следующим образом:
for key, value in hashes.iteritems():
if value != 0:
print "Uneven hash count: %s" % key
num_errors += 1
Также:
for line in f.readlines():
hashes[line] = hashes.setdefault(line, 0) + 1
... но я не могу помочь вам со стороной Ruby, кроме чтобы предложить вам выследить профилировщика.
Мне удалось немного ускорить ваш код Ruby следующим образом:
require 'benchmark'
Benchmark.bm(10) do |x|
x.report("original version") do
file = File.open("c:\\file1.txt", "r")
hashes = {}
file.each_line { |line|
if hashes.has_key?(line)
hashes[line] += 1
else
hashes[line] = 1
end
}
file.close()
#puts "Done file 1"
not_founds = 0
file = File.open("c:\\file2.txt", "r")
file.each_line { |line|
if hashes.has_key?(line)
hashes[line] -= 1
else
not_founds += 1
end
}
file.close()
#puts "Done file 2"
num_errors = 0
hashes.each_key{ |key|
if hashes[key] != 0
num_errors += 1
end
}
puts "Total of #{not_founds} lines not found in file2"
puts "Total of #{num_errors} mismatches found"
end
x.report("my speedup") do
hashes = {}
File.open("c:\\file1.txt", "r") do |f|
lines = f.readlines
lines.each { |line|
if hashes.has_key?(line)
hashes[line] += 1
else
hashes[line] = 1
end
}
end
not_founds = 0
File.open("c:\\file2.txt", "r") do |f|
lines = f.readlines
lines.each { |line|
if hashes.has_key?(line)
hashes[line] -= 1
else
not_founds += 1
end
}
end
num_errors = hashes.values.to_a.select { |z| z != 0}.size
puts "Total of #{not_founds} lines not found in file2"
puts "Total of #{num_errors} mismatches found"
end
end
поэтому я читаю файлы одним фрагментом ошибки, в моем случае это немного быстрее (я тестировал в Windows XP, ruby 1.8.6 и файл 100000 строк). I benchmarked all different ways to read files (i could think off), and this was the fastest way. Also i did speed up the counting of the values in a hash a bit, but this is only visible if you did it for very large numbers :)
So i get a very small speed-increase here. The output on my machine is as follows:
user system total real
original versionTotal of 16 lines not found in file2
Total of 4 mismatches found
1.000000 0.015000 1.015000 ( 1.016000)
my speedup v1Total of 16 lines not found in file2
Total of 4 mismatches found
0.812000 0.047000 0.859000 ( 0.859000)
Who has any ideas to improve this further?
If the f.readlines
goes slower, because of the size, i found that
File.open("c:\\file2.txt", "r") do |f|
while (line=f.gets)
if hashes.has_key?(line)
hashes[line] -= 1
else
not_founds += 1
end
end
end
is just a tad quicker for me.
I was thinking about about a way to improve the
if hashes.has_key?(line) ...
code a bit, but could not think of anything.
Have you tried using Ruby 1.9?
I have a Windows 7 Virtual Machine with Ruby 1.9.1, and there the f.readlines
was slower, and i needed to use the while (line=f.gets)
because of the memory limitations :)
Since a lot uf Ruby users test mainly on Unix related platforms, i guess that could explain why the code is sub-optimal on Windows. Has anybody compared the above mentioned performance on Unix? Is this a ruby vs. python problem, or Ruby-windows vs. Ruby-Unix?
I'm not a Ruby expert, so someone please correct me if I'm wrong:
I see a small optimization potential.
If you say
hashes = hash.new(0)
then a reference to an undefined hash will return 0 and store the key; and you can do
hashes[line] += 1
every time, without the enclosing if
and else
.
Caveat: Untested!
If storing the key doesn't happen automatically, there's yet another hash constructor using a block where you can do it explicitly.
Словарь Python очень быстр. См. Как реализованы встроенные словари Python Возможно, Ruby не так уж и хорош.
Я сомневаюсь, что дело в хэш-функциях. У разработчиков Ruby нет возможности создать хеш-функцию, которая на порядок хуже, чем у Python.
Возможно, Ruby 1.8 медленно динамически изменяет размер больших хеш-таблиц? Как ваша проблема масштабируется с файлами меньшего размера?