java - 如何在Java 7中以内存效率写入多个大文件

标签 java java-io filewriter bufferedwriter

我需要将大量数据(我可以在一秒钟内获取最多1KB的数据)写入多个不同的文件(每个文件最多可以占用几个GiB的空间。

在我的应用程序中,一个线程不断生成数据,目前我正在为每个文件创建一个线程来写入数据(创建新文件取决于生产者正在生成的输入数据的某些标准)。

我正在使用由 BufferedWriter 包装的 FileWriter。最初我尝试使用默认缓冲大小 8KB 进行写入。但由于这使得每秒写入次数更高,因此 CPU 消耗迅速增加而不下降。

所以,我现在已将缓冲大小增加到 50KB。 但这导致我的应用程序由于内存不足问题而崩溃。

当我分析它时,我可以看到所有数据都以 char 数组的形式存储,该数组是由缓冲写入器创建的(记住每个文件一个缓冲写入器。我有大约 400 个这样的文件)。

请建议如何解决这里的问题。 我还想知道是否有任何替代方案或更好的方法来实现该要求。

我无法将缓冲区大小减少到 50KB 以下,因为这会使我的 CPU 利用率达到 100%。

编辑:好吧,我想我不需要添加代码,因为我可以把需求说得很清楚(而且我与代码无关。没关系,只是我追求效率)。但由于我的问题被否决,所以我在此处包含我的代码。

public class DataWriter {

      private LinkedBlockingQueue<MyDataObject> dataQueue = new LinkedBlockingQueue<>();
      private ExecutorService singleThread = Executors.newSingleThreadExecutor();
      private boolean isRunning = true;
      private Map<String, FileWriterThread> map = Collections.synchronizedMap(new HashMap<String, FileWriterThread>());

      public DataWriter() {
         singleThread.submit(new DataProcessor());
      }

      public void writeProducedData(MyDataObject object) {
          if (isRunning) {
             dataQueue.offer(object);
          }
      }

      public void stopWriting() {
          isRunning = false;
      }

      private class DataProcessor implements Runnable {

         @Override
         public void run() {
            while (isRunning) {

            MyDataObject obj = dataQueue.take();

            if (obj.getMapKey() == null) {
                FileWriterThread thread = new FileWriterThread();
                map.put(obj.getMapKey(), thread);
            }

            FileWriterThread thread = map.get(obj.getMapKey());
            thread.writeData(obj);
         }
        }        
      }
    }

FileWriterThread 类:

public class FileWriterThread {

       private ExecutorService singleThread = Executors.newSingleThreadExecutor();
       private FileWriter fileWriter;
       private BufferedWriter bufferedWriter;
       private LinkedBlockingQueue<MyDataObject> dataQueue = new LinkedBlockingQueue<>();

    public FileWriterThread() {
      singleThread.submit(new DataProcessor());
    }

    public void writeData(MyDataObject obj) {
     if (fileWriter == null) {
       createWriter(obj.getFileName());
     }
     dataQueue.offer(obj);
    }

    public void stopWriting() {
      // close the file writer and buffer writer gracefully
    }

    private void createWriter(String fileName) {
      try {
        fileWriter = new FileWriter(fileName, true);
        bufferedWriter = new BufferedWriter(fileWriter, 50);
      } catch (Exception e){}   
    }

    private class DataProcessor implements Runnable {

       @Override
       public void run() {
         MyDataObject obj =  dataQueue.take();
         try {
           bufferedWriter.write(obj.toString());
         } catch(Exception e) {}
       }
    }
  }

最佳答案

拥有所有这些线程不会给你带来任何好处——整个事情都是 IO 绑定(bind)的,而不是 CPU 绑定(bind)的(或者将会是,如果你的 CPU 没有努力处理 400 个线程的话)。

在单个线程中,只需让您的生产者写入适当的写入器:

   Map<String, Writer> writers = ...;

   private handleOutput(byte[] output, String key) {
        writers.get(key).write(output);
   }

如果您想分离您的关注点,可能需要几个(而不是数百个)线程用于写入,一个用于生成,请使用队列将它们分开。

关于java - 如何在Java 7中以内存效率写入多个大文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46100270/

相关文章:

java - NOTIFICATION_RECEIVER 无法解析为变量

sockets - 用 Java 套接字重现写-写-读延迟

java - 使用Java进行文件分割的问题

java - 文件输入流空指针异常

java - 将二维数组传输到文件并传回

Java 将输入追加到文件

java - `java.nio.file.Files.createFile` 是阻塞调用吗?

java - JSON 错误 "java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $"

java - 如何修复运行时错误 : java. lang.ArrayIndexOutOfBoundsException: 0

java - 如何使用 Java 中的 FileWriter 写入新行?