设计思路
- Ruby 特性:
- 使用 Ruby 的块(block)和迭代器(iterator)特性,以避免一次性将整个大文件读入内存。例如,
each_line
方法可以逐行读取文件,这样可以显著减少内存占用。
- 利用 Ruby 的哈希表(Hash)数据结构来存储单词及其频率。哈希表在查找和插入操作上具有较好的性能,平均时间复杂度为 O(1)。
- 库:
parallel
库:用于实现多线程或多进程处理多个文件,提高整体处理速度。这个库提供了简单易用的接口来并行执行任务。
trollop
库(可选):用于处理命令行参数,使工具的使用更加方便和灵活。
- 内存管理:
- 如前面提到,逐行读取文件,避免将整个文件加载到内存中。对于每个文件,在读取每一行时,对行中的单词进行处理并更新哈希表。
- 当处理完一个文件后,可以考虑在适当的时候释放一些不再使用的内存,例如通过将一些对象设置为
nil
并触发垃圾回收(虽然 Ruby 的垃圾回收机制相对自动,但手动干预有时也是必要的)。
- 多线程:
- 使用
parallel
库来并行处理多个文件。每个文件的处理可以看作是一个独立的任务,并行执行这些任务可以充分利用多核 CPU 的优势,加快整体处理速度。但要注意线程安全问题,在并行更新共享数据(如全局的单词频率统计结果)时需要使用线程锁(Mutex)。
简化版本核心逻辑代码
require 'parallel'
def process_file(file_path)
word_frequency = {}
File.foreach(file_path) do |line|
line.split.each do |word|
word_frequency[word] ||= 0
word_frequency[word] += 1
end
end
word_frequency
end
def merge_frequency(freq1, freq2)
result = freq1.dup
freq2.each do |word, count|
result[word] ||= 0
result[word] += count
end
result
end
file_paths = ARGV
all_frequencies = Parallel.map(file_paths) do |file_path|
process_file(file_path)
end
total_frequency = all_frequencies.reduce(&method(:merge_frequency))
sorted_frequency = total_frequency.sort_by { |_word, count| -count }
sorted_frequency.each do |word, count|
puts "#{word}: #{count}"
end
关键优化点
- 逐行读取:使用
File.foreach
逐行读取文件,减少内存占用。
- 并行处理:通过
Parallel.map
并行处理多个文件,提高处理速度。
- 哈希表使用:利用哈希表高效的查找和插入特性来统计单词频率。
- 合并结果:使用
reduce
方法合并每个文件的单词频率统计结果,保持代码简洁和高效。