2016-10-20 5 views
0

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

class DataProcessor{ 
    public List<Record> processData(DataFile file){ 
     List<Record> recordsList = new ArrayList<Record>(); 
     for(Line line : file.getLines()){ 
      String processedData = processData(line); 
      recordsList.add(new Record(processedData)); 
     } 
    } 

    private String processData(String rawLine){ 
     //code to process line 
    } 
} 
class DatabaseManager{ 
    saveRecords(List<Record> recordsList){ 
     //code to insert records objects in database 
    } 
} 
class Manager{ 
    public static void main(String[] args){ 

     DatabaseManager dbManager = new DatabaseManager("e:\\databasefile.db"); 
     DataFile dataFile = new DataFile("e:\\hugeRawFile.csv"); 
     DataProcessor dataProcessor = new DataProcessor(); 
     dbManager.saveRecords(dataProcessor.processData(dataFile)); 
    } 
} 

Как вы можете видеть, метод «ProcessData» класса «DataProcessor» принимает объект DataFile, обрабатывает весь файл, создавать объект записи для каждой строки, а затем он возвращает список объектов «Запись».

Моя проблема с методом processData: когда необработанный файл действительно огромен, объекты «Список записей» занимают много памяти, а иногда программа терпит неудачу. Мне нужно изменить текущий desgin так, чтобы использование памяти было сведено к минимуму. «DataProcessor» не должен иметь прямого доступа к «DatabaseManager». Я думал о передаче очереди методу processData, где один поток запускал метод processData для вставки объекта «Запись» в очередь, а другой поток удалял объект «Запись» из очереди и вставлял его в базу данных. Но я не уверен в проблемах с этим.

ответ

0

Вы должны иметь возможность использовать потоковое вещание для этого в одном потоке, по одной записи за раз в памяти. Реализация зависит от технологии, используемой вашим DatabaseManager.

+0

не могли бы вы уточнить? DatabaseManager использует JDBC-интерфейс для SQLite и просто простой подготовленный оператор, где я получаю значения из объекта «Запись» и помещаю их в оператор «insert», а затем выполняю это вставку. –

+1

вот пример: https://tododev.wordpress.com/2014/08/14/creating-and-object-stream-from-a-jdbc-resultset/ –

1

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

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

class DataProcessor{ 
    public List<Record> processData(DataFile file){ 
     List<Record> recordsList = new ArrayList<Record>(); 
     for(Line line : file.getLines()){ 
      String processedData = processData(line); 
      recordsList.add(new Record(processedData)); 
     } 
    } 

    private String processData(String rawLine){ 
     //code to process line 
    } 

    public void processAndSaveData(DataFile dataFile, DatabaseManager db) { 
     int maxBuffSize=1024; 
     ArrayList<Record> buff=new ArrayList<Record>(maxBuffSize); 
     for(Line line : file.getLines()){ 
     String processedData = processData(line); 
     buff.add(new Record(processedData)); 
     if(buff.size()==maxBuffSize) { 
      db.saveRecords(buff); 
      buff.clear(); 
     } 
     } 
     // some may be still unsaved here, less that maxBuffSize 
     if(buff.size()>0) { 
     db.saveRecords(buff); 
     // help the CG, let it recycle the records 
     // without needing to look "is buff still reacheable"? 
     buff.clear(); 
     } 
    } 
} 

class Manager{ 
    public static void main(String[] args){ 

     DatabaseManager dbManager = new DatabaseManager("e:\\databasefile.db"); 
     DataFile dataFile = new DataFile("e:\\hugeRawFile.csv"); 
     DataProcessor dataProcessor = new DataProcessor(); 

     // So... do we need another stupid manager to tell us what to do? 
     // dbManager.saveRecords(dataProcessor.processData(dataFile)); 

     // Hell, no, the most constrained resource knows better 
     // how to deal with the job! 
     dataProcessor.processAndSaveData(dataFile, dbManager); 
    } 
} 

[править] Обращаясь к «но мы остановились на что и как, и теперь вы приезжаете, чтобы сказать нам, что мы должны писать дополнительный код?»

Постройте класс AbstractProcessor и попросите своих помощников только получить от него.

class AbstractProcessor { 
    // sorry, need to be protected to be able to call it 
    abstract protected Record processData(String rawLine); 

    abstract protected Class<? extends Record> getRecordClass(); 

    public void processAndSaveData(DataFile dataFile, DatabaseManager db) { 
    Class<? extends Record> recordType=this.getRecordClass(); 
    if(recordType.equals(MyRecord1.class) { 
     // buffered read and save MyRecord1 types specifically 
    } 
    else if(recordType.equals(YourRecord.class)) { 
     // buffered read and save YourRecord types specifically 
    } 
    // etc... 
    } 
} 

Теперь все, что нужно сделать, это «код» extends AbstractProcessor и сделать их защитой processData(String) и написать тривиальный метод объявляющий его тип записи (а может быть перечисление). Не похоже, чтобы вы задавали им огромные усилия и делали то, что было бы дорогостоящим (или даже невозможным для работы с входным файлом TB) «как можно быстрее».

+0

спасибо за это. на самом деле у меня было что-то подобное. Но в моей реальной программе у меня много классов расширяет «DataProcessor» для разных типов данных. Эти классы разрабатываются разными разработчиками, а требование «классы Dataprocessor» не должно быть ничего, кроме файла данных, и ничего не знать о классе «DatabaseManager». Поэтому я переработал код, похожий на мой упомянутый код, но потом у меня возникла проблема с памятью. и кстати я все еще начинающий программист. –

+1

@ AnthonyJ. Ну, см. Мои дополнительные комментарии в конце моего ответа.Если ваши товарищи не согласны, вы обречены на это с этой задачей - никоим образом не обойти это. –

+0

еще раз спасибо и да, это не потребует много работы на их стороне. но мне интересно, почему вы думаете, что очередь не будет работать? если «Менеджер» передает очередь на «DataProcessor», тогда «Менеджер» берет «Записи» из этой очереди и передает их в «Менеджер баз данных». –

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

  • Нет связанных вопросов^_^