我需要将大量数据(我可以在一秒内获得高达1KB的数据)写入多个不同的文件(每个文件可以增加几个GiB的空间。
在我的应用程序中,一个线程不断生成数据,目前我正在为每个文件创建一个线程来写入数据(创建一个新文件取决于生产者正在生成的输入数据的某些标准)。
我正在使用由BufferedWriter包装的FileWriter。最初我尝试使用默认缓冲大小8KB进行写入。但由于这会使每秒的写入次数更高,因此CPU消耗会迅速增加而不会降低。
所以,我现在已经将缓冲大小增加到50KB。 但是由于outOfMemory问题,这使我的应用程序崩溃。
当我对它进行分析时,我可以看到所有数据都以char数组的形式存储,这是由缓冲的编写器创建的(记住每个文件有一个缓冲的编写器。我有大约400个这样的文件)。< / p>
请建议如何克服这个问题。 我还想知道是否有任何替代方案或更好的方法来实施该要求。
我无法将缓冲区大小减小到小于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) {}
}
}
}
答案 0 :(得分:0)
让所有这些线程一无所获 - 整个事情都是IO绑定的,而不是CPU限制的(或者,如果你的CPU没有努力去处理400个线程)。
在单个线程中,让生产者写入相应的编写者:
Map<String, Writer> writers = ...;
private handleOutput(byte[] output, String key) {
writers.get(key).write(output);
}
如果你想分开你的顾虑,可能有一些(不是数百)线程用于写作,一个用于制作,用Queue
分隔它们。