我可以使用什么数据结构或设计模式来解决此问题

时间:2016-10-20 07:16:55

标签: java design-patterns data-structures queue heap-memory

我有以下设计问题,希望能帮到您解决。 下面简单介绍一下代码的含义

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));
    }
}

如您所见,&#34; processData&#34;类的方法&#34; DataProcessor&#34;获取DataFile对象,处理整个文件,为每一行创建Record对象,然后返回一个&#34; Record&#34;对象。

我的问题&#34; processData&#34;方法:当原始文件非常庞大时,&#34;记录列表&#34;对象需要大量内存,有时程序会失败。我需要更改当前的设计,以便最大限度地减少内存使用量。 &#34;数据处理器&#34;不应该直接访问&#34; DatabaseManager&#34;。 我正在考虑将队列传递给&#34; processData&#34;方法,其中一个线程运行&#34; processData&#34;插入&#34;记录&#34;的方法队列中的对象,而另一个线程删除&#34;记录&#34;队列中的对象并将其插入数据库中。但我不确定这方面的性能问题。

2 个答案:

答案 0 :(得分:1)

将驱动流程的责任放入最受约束的资源(在您的情况下为DataProcessor) - 这将确保最好地遵守约束而不是强制到断点。

注意:甚至不考虑多线程,它对处理文件没有任何帮助。线程将是一个解决方案,如果您的数据通过线路,当您不知道下一个数据块何时到达时,或许您有更好的事情来处理您的CPU时间而不是等待“直到奶牛回到栖息地“(笑)。但是有文件吗?你知道这份工作有一个开始和结束,所以尽可能快地继续工作。

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输入文件)。

答案 1 :(得分:0)

您应该能够使用流媒体在一个线程中执行此操作,在内存中一次执行一条记录。实现取决于您的DatabaseManager正在使用的技术。