多线程使java大文件处理变得更糟糕
我正在用java测试一个大文件(10.000.100行)的处理 我编写了一段代码,从文件中读取并生成指定数量的线程(最多等于CPU的内核),然后将文件行的内容打印到标准输出多线程使java大文件处理变得更糟糕,java,multithreading,Java,Multithreading,我正在用java测试一个大文件(10.000.100行)的处理 我编写了一段代码,从文件中读取并生成指定数量的线程(最多等于CPU的内核),然后将文件行的内容打印到标准输出 Main类如下所示: public class Main { public static void main(String[] args) { int maxThread; ArrayList<String> linesForWorker = new ArrayLi
Main
类如下所示:
public class Main
{
public static void main(String[] args)
{
int maxThread;
ArrayList<String> linesForWorker = new ArrayList<String>();
if ("MAX".equals(args[1]))
maxThread = Runtime.getRuntime().availableProcessors();
else
maxThread = Integer.parseInt(args[1]);
ExecutorService executor = Executors.newFixedThreadPool(maxThread);
String readLine;
Thread.sleep(1000L);
long startTime = System.nanoTime();
BufferedReader br = new BufferedReader(new FileReader(args[0]));
do
{
readLine= br.readLine();
if ("X".equals(readLine))
{
executor.execute(new WorkerThread((ArrayList) linesForWorker.clone()));
linesForWorker.clear(); // Wrote to avoid storing a list with ALL the lines of the file in memory
}
else
{
linesForWorker.add(readLine);
}
}
while (readLine!= null);
executor.shutdown();
br.close();
if (executor.awaitTermination(1L, TimeUnit.HOURS))
System.out.println("END\n\n");
long endTime = System.nanoTime();
long durationInNano = endTime - startTime;
System.out.println("Duration in hours:" + TimeUnit.NANOSECONDS.toHours(durationInNano));
System.out.println("Duration in minutes:" + TimeUnit.NANOSECONDS.toMinutes(durationInNano));
System.out.println("Duration in seconds:" + TimeUnit.NANOSECONDS.toSeconds(durationInNano));
System.out.println("Duration in milliseconds:" + TimeUnit.NANOSECONDS.toMillis(durationInNano));
}
}
class WorkerThread implements Runnable
{
private List<String> linesToPrint;
public WorkerThread(List<String> linesToPrint) { this.linesToPrint = linesToPrint; }
public void run()
{
for (String lineToPrint : this.linesToPrint)
{
System.out.println(String.valueOf(Thread.currentThread().getName()) + ": " + lineToPrint);
}
this.linesToPrint = null; // Wrote to help garbage collector know I don't need the object anymore
}
}
我运行的应用程序指定1和“MAX”(即CPU核心的数量,在我的情况下是4)作为FixedThreadPool的最大线程,我经历了:
- 使用
中的一个单线程执行应用程序时,执行时间约为40分钟李>FixedThreadPool
- 使用
中的4个线程执行应用程序时,执行时间约为44分钟FixedThreadPool
为什么多线程版本仍然更持久?可能每个线程,即使是要写入其“个人”文件,也必须等待其他线程释放SSD资源,以便访问和写入它?您使用一个线程读取文件行。从HDD或SSD的多个线程读取文件内容对您没有好处(HDD会崩溃,性能会更差),所以这没关系
System.out.println
是一个同步函数,它可能会极大地限制您的处理线程。我们说的是多少行?40分钟似乎是极端的。您可能受到IO限制,或者受到有关System.out.println
的争论的困扰。请注意,克隆您的ArrayList是不必要的开销。只需按原样传递ArrayList,并指定ArrayList的新实例,而不是清除旧实例。您还可以创建比默认值16大的ArrayList。您发布的代码中唯一的多线程部分是文件内容的打印,甚至不是真正的多线程,因为您没有同时启动线程。可能是一个给定的线程在下一个线程开始之前就完成了。在这种情况下,启动额外线程的开销只会增加代码执行时间!这些文件包含10.000.100行,正如我在问题开头所写的,我建议您缓冲控制台输出(描述了一种简单的方法,但我会在内存中使用某种线程安全列表)在写入System.out
之前,请使用另一种方式使用适当的日志框架记录数据,例如支持异步日志记录。如果你的代码真的是你发布的1:1,它就不应该像你描述的那样长(只有当你在一些非常旧的机器上运行或者有一个坏掉的ssd时)。我的建议是:不要在生产中使用System.out.println
,您只需一个线程即可读取文件行。从HDD或SSD的多个线程读取文件内容对您没有好处(HDD会崩溃,性能会更差),所以这没关系System.out.println
是一个同步函数,它可能会极大地限制您的处理线程。我们说的是多少行?40分钟似乎是极端的。您可能受到IO限制,或者受到有关System.out.println
的争论的困扰。请注意,克隆您的ArrayList是不必要的开销。只需按原样传递ArrayList,并指定ArrayList的新实例,而不是清除旧实例。您还可以创建比默认值16大的ArrayList。您发布的代码中唯一的多线程部分是文件内容的打印,甚至不是真正的多线程,因为您没有同时启动线程。可能是一个给定的线程在下一个线程开始之前就完成了。在这种情况下,启动额外线程的开销只会增加代码执行时间!这些文件包含10.000.100行,正如我在问题开头所写的,我建议您缓冲控制台输出(描述了一种简单的方法,但我会在内存中使用某种线程安全列表)在写入System.out
之前,请使用另一种方式使用适当的日志框架记录数据,例如支持异步日志记录。如果你的代码真的是你发布的1:1,它就不应该像你描述的那样长(只有当你在一些非常旧的机器上运行或者有一个坏掉的ssd时)。我的建议是:不要在生产中使用System.out.println