2010-07-22 8 views
1

В моей программе используется два больших текстовых файла (Миллионы строк). Эти файлы анализируются и загружаются в хэши, чтобы можно было быстро получить доступ к данным. Проблема, с которой я сталкиваюсь, заключается в том, что в настоящее время синтаксический анализ и загрузка являются самой медленной частью программы. Ниже приведен код, где это делается.Увеличение скорости загрузки больших файлов

database = extractDatabase(@type).chomp("fasta") + "yml" 
revDatabase = extractDatabase(@type + "-r").chomp("fasta.reverse") + "yml" 
@proteins = Hash.new 
@decoyProteins = Hash.new 

File.open(database, "r").each_line do |line| 
    parts = line.split(": ") 
    @proteins[parts[0]] = parts[1] 
end 

File.open(revDatabase, "r").each_line do |line| 
    parts = line.split(": ") 
    @decoyProteins[parts[0]] = parts[1] 
end 

И файлы выглядят как пример ниже. Он начинался как файл YAML, но формат был изменен для увеличения скорости разбора.

MTMDK: P31946 Q14624 Q14624-2 B5BU24 B7ZKJ8 B7Z545 Q4VY19 B2RMS9 B7Z544 Q4VY20 
MTMDKSELVQK: P31946 B5BU24 Q4VY19 Q4VY20 
.... 

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

Есть ли способ улучшить скорость этого, или есть целый другой подход, который я могу принять?

Список вещей, которые не работают:

  • YAML.
  • Стандартные рубиновые нити.
  • Снятие процессов, а затем извлечение хеша через трубу.
+0

Как насчет написания расширения C? – CodeJoust

+0

Вы используете Ruby 1.8 или 1.9? 1.9 может быть на 10-20% быстрее, чем 1,8 (для окон такого типа это еще больше). – Digikata

+0

Я использую 1.9.1 –

ответ

2

В моем использовании, читая все или частично файл в памяти перед разбором, обычно идет быстрее. Если размеры баз данных достаточно малы, это может быть столь же просто, как

buffer = File.readlines(database) 
buffer.each do |line| 
    ... 
end 

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

+0

Это позволило сбрить примерно 30 секунд, но это занимает 2 минуты. –

+0

Я узнал, что после этого другие изменения метода уменьшили время. Благодаря этому и другим улучшениям, теперь до приемлемого времени. –

0

Я не слишком много знаю о Ruby, но перед этим мне пришлось иметь дело с проблемой. Я нашел, что лучший способ состоял в том, чтобы разбить файл на куски или отдельные файлы, а затем порождать потоки, чтобы читать каждый кусок за один раз. После того, как секционированные файлы находятся в памяти, объединение результатов должно быть быстрым. Вот некоторая информация о Threads в Ruby:

http://rubylearning.com/satishtalim/ruby_threads.html

Надежда, что помогает.

+0

Разве это действительно поможет? Потому что, как я уже упоминал, когда я использовал поток для каждого файла, он шел медленнее. –

2

Почему бы не использовать решение, разработанное на протяжении десятилетий опыта: база данных, скажем, SQLlite3?

+0

+1, хотя это может показаться неудовлетворительным после фазы «один раз» для простого ключа/значений. Другой вариант - это стиль BDB-стиля (Berkley-DB), если это просто хранилище ключей/значений и не требует дополнительных SQL-отношений и объединений. – 2010-07-22 21:02:04

1

(Чтобы быть разными, хотя я бы первым рекомендую посмотреть на (Ruby) BDB и другие «NoSQL» серверных двигателях, если они соответствуют вашим потребностям.)

Если фиксированного размером запись с детерминированным индексом является то вы можете выполнять ленивую загрузку каждого элемента через прокси-объект. Это было бы подходящим кандидатом для mmap. Однако это будет не ускорить общее время доступа, а просто амортизирует загрузку в течение всего жизненного цикла программы (по крайней мере, до первого использования, и если некоторые данные никогда не используются, тогда вы получаете возможность никогда не загружать его). Без фиксированных записей или детерминированных значений индекса эта проблема более сложна и начинает больше напоминать традиционный «индексный» магазин (например, B-дерево в SQL-back-end или любом BDB-приложении :-).

общие проблемы с резьб здесь:

  1. НЛ будет вероятно быть узким местом вокруг Руби «зеленых» нитей
  2. Вам все еще нужно все данные перед использованием

Вас может заинтересовать Widefinder Project, как правило, «пытается получить более быструю обработку ввода-вывода».

+0

Время, необходимое для создания базы данных, было невыносимым. –