Java Arrays.sort()需要很长时间

Java Arrays.sort()需要很长时间,java,sorting,Java,Sorting,我使用Java的Arrays.sort()函数按文件的上次修改时间对文件列表进行排序。对245个文件进行排序大约需要5秒钟。这对我来说太长了。我觉得不应该超过0.5秒。这是一个好的假设吗?我做错了什么?或者这听起来正常吗 public static class LastModifiedComparator implements Comparator<File> { @Override public int compare(File f1, File f2) {

我使用Java的
Arrays.sort()
函数按文件的上次修改时间对文件列表进行排序。对245个文件进行排序大约需要5秒钟。这对我来说太长了。我觉得不应该超过0.5秒。这是一个好的假设吗?我做错了什么?或者这听起来正常吗

public static class LastModifiedComparator implements Comparator<File> {
    @Override
    public int compare(File f1, File f2) {
        return (int)(f1.lastModified() - f2.lastModified());
    }       
}

File folder = new File( "C:\\Whatever\\" );
File[] filesInFolder = folder.listFiles();
logger.debug("Starting File Sort");
Arrays.sort(filesInFolder, new LastModifiedComparator());
logger.debug("Done File Sort");
公共静态类LastModifiedComparator实现Comparator{
@凌驾
公共整数比较(文件f1、文件f2){
返回(int)(f1.lastModified()-f2.lastModified());
}       
}
文件夹=新文件(“C:\\Whatever\\”;
File[]fileinfolder=folder.listFiles();
debug(“开始文件排序”);
sort(fileinfolder,new LastModifiedComparator());
debug(“完成文件排序”);
日志输出

2012-08-10 14:24:20,333 DEBUG http-8080-4 <ClassName>:73 - Starting File Sort
2012-08-10 14:24:25,915 DEBUG http-8080-4 <ClassName>:75 - Done File Sort
2012-08-10 14:24:20333调试http-8080-4:73-开始文件排序
2012-08-10 14:24:25915调试http-8080-4:75-完成文件排序

在java中以改进的快速排序调优合并排序实现的排序,其平均运行时复杂性为O(nlogn)
所以我们需要集中精力处理文件操作,例如获取lastModifiedTime。您确定这些文件是本地文件或共享驱动器,会占用网络延迟吗?

文件。lastModified
必须转到操作系统查询文件上次修改的时间,因为它没有缓存。每次比较要执行两次,并使用--
O(n logn)
。为
n
插入245,即大约580次比较,或者1100次调用操作系统以获取上次修改的时间。这意味着您每秒可以收到大约230个最后修改的呼叫。这看起来可能有点慢,但肯定比在JVM中进行这么长时间的比较更合理


正如Marko Topolnik abd NgSan在上面指出的,修复方法是首先缓存所有文件的上次修改时间。我将通过创建一个新的类对象来实现这一点,该类对象组合了文件和时间,然后对这些对象进行排序。这样,您将只有245次调用
File.lastModified
,而排序将花费大约五分之一的时间。

我不确定,但听起来好像每次读取修改的时间时它都在进行磁盘I/O操作,因此速度较慢。将对象中的修改时间与文件对象一起获取,然后进行排序可能会更快。

您需要改进
比较器的逻辑。您需要缓存
lastModified()
值,因为该方法的实现非常缓慢。我建议将
文件
实例包装到您制作的可比较对象中,以缓存值:

public class FileLmWrapper implements Comparable<FileLmWrapper> {
  public final File f;
  public final long lastModified;
  public FileLmWrapper(File f) { 
    this.f = f; 
    lastModified = f.lastModified();
  }
  public int compareTo(FileLmWrapper other) {
    return Long.compare(this.lastModified, other.lastModified);
  }
}
public类FileLmWrapper实现可比较的{
公共最终文件f;
最后修改的公共文件;
公共文件包装器(文件f){
这个。f=f;
lastModified=f.lastModified();
}
public int compareTo(FileLmWrapper其他){
返回Long.compare(this.lastModified,other.lastModified);
}
}
您的比较操作

@Override
public int compare(File f1, File f2) {
    return (int)(f1.lastModified() - f2.lastModified());
}  

不仅仅是一个getter,它还发出一个从文件系统获取信息的调用,因此排序的高响应时间还要归功于
lastModified()
的性能,而不是
compare()

如果文件是唯一的(所有文件都有不同的equals方法),那么使用TreeSet看看会发生什么会很有趣。您可能需要将该文件包装到另一个实现comparator的类中。5秒看起来确实很长时间!文件夹中有多少个文件?您也尝试过将其作为集合,并使用ArrayList和Collections.sort()。这有什么不同吗?你没有告诉我们你正在排序的数组有多大。很可能数组非常大,这里假设所有的
O(n logn)
都来自比较。真的是这样吗?还有复制和合并。我想大部分是,是的。我做了一个快速的小测试,结果显示:(警告:会给你的工作目录发送大量的空文件!)@MarkoTopolnik,为了解决这个问题:当我在我的机器上运行这个程序时,ints进行了1721次比较,耗时2.1毫秒。这些文件进行了244次比较(它们都有相同的上次修改时间,因为它们创建得如此之快,所以排序只是
O(n)
),仍然需要5.5毫秒。如果文件是按修改日期随机排序的,则需要大约39.0毫秒(仍然比OP快得多!我不知道他的磁盘出了什么问题).是的,那会更有意义。实际上是合并排序,它比快速排序做的比较少,但要消耗更多的内存。谢谢你纠正我,你是对的。实际上,它只对基本类型进行了快速排序,但对于对象,实现了合并排序。谢谢,包装器工作得很好!排序是在现在是毫秒级。但是,整个操作仍然需要大约1秒。我猜构建那些245
FileLmWrapper
对象需要时间。也许我应该尝试将时间放在HashMap中,而不是使用包装器!@Danish 245对象分配几乎不需要时间。如果你看我下面的帖子,我会采取行动通过推断每次调用
lastModified()
所需的时间,我预测您大约需要1秒。是的,您正确地预测了将定义此操作运行时下限的
lastModified()
。@尽管如此,我仍然不知道为什么需要1秒。245次调用
lastModified()
在我的功能不太强大的笔记本电脑上花费了大约5.5毫秒。@yshavit可能是因为文件夹位于网络驱动器上。这是我在问题中没有提到的一条信息。