Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Java文件写入会消耗CPU?_Java_Queue_Bufferedwriter - Fatal编程技术网

为什么Java文件写入会消耗CPU?

为什么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

我使用一个单独线程上的队列将数据写入文件,但该进程消耗了大约25%的CPU,如本测试主代码所示

我能做些什么来解决这个问题吗

也许我应该在某个地方使用flush()

测试显示主方法启动并运行队列线程,然后将创建的数据发送给它。队列线程将数据写入BufferedWriter,后者负责将数据写入文件

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
}