为什么Java文件写入会消耗CPU?
我使用一个单独线程上的队列将数据写入文件,但该进程消耗了大约25%的CPU,如本测试主代码所示 我能做些什么来解决这个问题吗 也许我应该在某个地方使用flush() 测试显示主方法启动并运行队列线程,然后将创建的数据发送给它。队列线程将数据写入BufferedWriter,后者负责将数据写入文件为什么Java文件写入会消耗CPU?,java,queue,bufferedwriter,Java,Queue,Bufferedwriter,我使用一个单独线程上的队列将数据写入文件,但该进程消耗了大约25%的CPU,如本测试主代码所示 我能做些什么来解决这个问题吗 也许我应该在某个地方使用flush() 测试显示主方法启动并运行队列线程,然后将创建的数据发送给它。队列线程将数据写入BufferedWriter,后者负责将数据写入文件 import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOExce
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import uk.co.moonsit.utils.timing.Time;
public class OutputFloatQueueReceiver extends Thread {
private static final Logger LOG = Logger.getLogger(OutputFloatQueueReceiver.class.getName());
private ConcurrentLinkedQueue<List<Float>> queue = null;
private boolean running = true;
private final BufferedWriter outputWriter;
private int ctr = 0;
private final int LIMIT = 1000;
public OutputFloatQueueReceiver(String outputFile, String header, ConcurrentLinkedQueue<List<Float>> q) throws IOException {
queue = q;
File f = new File(outputFile);
FileWriter fstream = null;
if (!f.exists()) {
try {
f.getParentFile().mkdirs();
if (!f.createNewFile()) {
throw new IOException("Exception when trying to create file " + f.getAbsolutePath());
}
fstream = new FileWriter(outputFile, false);
} catch (IOException ex) {
//Logger.getLogger(ControlHierarchy.class.getName()).log(Level.SEVERE, null, ex);
throw new IOException("Exception when trying to create file " + f.getAbsolutePath());
}
}
fstream = new FileWriter(outputFile, true);
outputWriter = new BufferedWriter(fstream);
outputWriter.append(header);
}
public synchronized void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
while (running) {
while (queue.peek() != null) {
if (ctr++ % LIMIT == 0) {
LOG.log(Level.INFO, "Output Queue size = {0} '{'ctr={1}'}'", new Object[]{queue.size(), ctr});
}
List<Float> list = queue.poll();
if (list == null) {
continue;
}
try {
StringBuilder sbline = new StringBuilder();
Time t = new Time(list.get(0));
sbline.append(t.HMSS()).append(",");
for (Float f : list) {
sbline.append(f).append(",");
}
sbline.append("\n");
outputWriter.write(sbline.toString());
} catch (IOException ex) {
LOG.info(ex.toString());
break;
}
}
}
if (outputWriter != null) {
try {
outputWriter.close();
LOG.info("Closed outputWriter");
} catch (IOException ex) {
Logger.getLogger(OutputFloatQueueReceiver.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public static void main(String[] args) {
try {
String outputFile = "c:\\tmp\\qtest.csv";
File f = new File(outputFile);
f.delete();
StringBuilder header = new StringBuilder();
header.append("1,2,3,4,5,6,7,8,9");
header.append("\n");
ConcurrentLinkedQueue<List<Float>> outputQueue = null;
OutputFloatQueueReceiver outputQueueReceiver = null;
outputQueue = new ConcurrentLinkedQueue<>();
outputQueueReceiver = new OutputFloatQueueReceiver(outputFile, header.toString(), outputQueue);
outputQueueReceiver.start();
for (int i = 1; i < 100000; i++) {
List<Float> list = new ArrayList<>();
//list.set(0, (float) i); // causes exception
list.add((float) i);
for (int j = 1; j < 10; j++) {
list.add((float) j);
}
outputQueue.add(list);
}
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
Logger.getLogger(OutputFloatQueueReceiver.class.getName()).log(Level.SEVERE, null, ex);
}
outputQueueReceiver.setRunning(false);
} catch (IOException ex) {
Logger.getLogger(OutputFloatQueueReceiver.class.getName()).log(Level.SEVERE, null, ex);
}
}
导入java.io.BufferedWriter;
导入java.io.File;
导入java.io.FileWriter;
导入java.io.IOException;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.concurrent.ConcurrentLinkedQueue;
导入java.util.logging.Level;
导入java.util.logging.Logger;
import uk.co.moonsit.utils.timing.Time;
公共类OutputFloatQueueReceiver扩展线程{
私有静态最终记录器LOG=Logger.getLogger(OutputFloatQueueReceiver.class.getName());
私有ConcurrentLinkedQueue队列=null;
私有布尔运行=真;
专用最终缓冲写入程序outputWriter;
私有int ctr=0;
私人最终整数限制=1000;
public OutputFloatQueueReceiver(字符串outputFile、字符串头、ConcurrentLinkedQueue q)引发IOException{
队列=q;
文件f=新文件(输出文件);
FileWriter fstream=null;
如果(!f.exists()){
试一试{
f、 getParentFile().mkdirs();
如果(!f.createNewFile()){
抛出新IOException(“尝试创建文件时出现异常”+f.getAbsolutePath());
}
fstream=newfilewriter(outputFile,false);
}捕获(IOEX异常){
//Logger.getLogger(ControlHierarchy.class.getName()).log(Level.SEVERE,null,ex);
抛出新IOException(“尝试创建文件时出现异常”+f.getAbsolutePath());
}
}
fstream=newfilewriter(outputFile,true);
outputWriter=新的缓冲写入程序(fstream);
outputWriter.append(标题);
}
公共同步void setRunning(布尔运行){
这就是跑步;
}
@凌驾
公开募捐{
(跑步时){
while(queue.peek()!=null){
如果(ctr++%限制==0){
LOG.LOG(Level.INFO,“输出队列大小={0}'{'ctr={1}'}'”,新对象[]{Queue.size(),ctr});
}
List=queue.poll();
if(list==null){
持续
}
试一试{
StringBuilder sbline=新的StringBuilder();
时间t=新时间(list.get(0));
sbline.append(t.HMSS()).append(“,”);
用于(浮动f:列表){
sbline.append(f).append(“,”);
}
sbline.append(“\n”);
outputWriter.write(sbline.toString());
}捕获(IOEX异常){
LOG.info(例如toString());
打破
}
}
}
如果(outputWriter!=null){
试一试{
outputWriter.close();
LOG.info(“关闭的outputWriter”);
}捕获(IOEX异常){
Logger.getLogger(OutputFloatQueueReceiver.class.getName()).log(Level.SEVERE,null,ex);
}
}
}
公共静态void main(字符串[]args){
试一试{
String outputFile=“c:\\tmp\\qtest.csv”;
文件f=新文件(输出文件);
f、 删除();
StringBuilder标头=新的StringBuilder();
标题。附加(“1,2,3,4,5,6,7,8,9”);
标题。追加(“\n”);
ConcurrentLinkedQueue outputQueue=null;
OutputFloatQueueReceiver outputQueueReceiver=null;
outputQueue=新的ConcurrentLinkedQueue();
outputQueueReceiver=新的OutputFloatQueueReceiver(outputFile,header.toString(),outputQueue);
outputQueueReceiver.start();
对于(int i=1;i<100000;i++){
列表=新的ArrayList();
//set(0,(float)i);//导致异常
列表。添加((浮动)i);
对于(int j=1;j<10;j++){
列表。添加((浮动)j);
}
添加(列表);
}
试一试{
睡眠(5000);
}捕获(中断异常例外){
Logger.getLogger(OutputFloatQueueReceiver.class.getName()).log(Level.SEVERE,null,ex);
}
outputQueueReceiver.setRunning(false);
}捕获(IOEX异常){
Logger.getLogger(OutputFloatQueueReceiver.class.getName()).log(Level.SEVERE,null,ex);
}
}
}此代码是您的代码占用大量CPU的原因:
while (running) {
while (queue.peek() != null) {
// logging
List<Float> list = queue.poll();
if (list == null) {
continue;
}
// do stuff with list
}
}
take()
无限期地调用块,仅在有可用元素时返回,并将该元素作为结果返回。如果无限期阻塞是一个问题,您可以使用带有超时的poll(…)
,也可以安排其他线程中断被阻塞的线程。您是否尝试通过探查器运行此操作以查看实际消耗了这么多CPU?您的代码没有意义。这里所有的File.delete()
和File.createNewFile()
调用都是完全浪费时间<代码>新的FileWriter(…)已经在操作系统中完成了这一切。你迫使这一切发生两次。然后,如果文件不存在,这已经是一个冗余测试,您将(a)创建它,(b)在非附加模式下重新创建它,(c)无法关闭它,(d)泄漏它,以及(e)在附加模式下重新创建它。不要这样写代码。给文件系统一些信任。它已经知道该做什么了。换句话说,可以删除以f.exists()
测试开始的整个块,而无需以任何方式改变应用程序的语义,只是为了提高其效率。@EJP是的,这有点混乱,没有注意到我已经创建了两次fstream。按照你的建议做了,尽管需要保留MKDIR。谢谢,谢谢,好像就是这样。我想我已经考虑过封锁队列了
while (running) {
List<Float> list = queue.take();
// do stuff with list
}