使用多线程对文件进行排序

时间:2011-12-24 20:47:49

标签: java multithreading file sorting

我通过读取块(Arraylist)来排序大文件,使用Collections.sort使用自定义比较器对每个arraylist进行排序,并将排序后的结果写入文件,然后对所有文件应用合并排序算法。

我是在一个帖子里做的。

如果我为每个Collections.sort()启动一个新线程,我会获得任何性能提升吗?

我的意思是以下内容:
我从文件读入List,当List已满时,我开始一个新的线程,我对这个List进行排序并写入临时文件。

同时我继续从文件中读取并在列表再次填满时启动一个新线程...

我有另一个问题:

分类更好:
1)我填写的Arraylist,当它完整时,应用collections.sort()
2)我填写的TreeMap,我不需要对它进行排序。 (当我插入项目时,它就是各种各样的)

注意:我使用的是JAVA 1.5

更新: 这是我想要使用的代码,问题是我正在重用使用线程所使用的数据线arraylist而且我需要等到所有线程都完成。 我该如何解决?

int MAX_THREADS = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);
List datalines = ArrayList();       
try {
   while (data != null) {
       long currentblocksize = 0;

    while ((currentblocksize <= blocksize) && (data = getNext()) != null) {
                                        datalines.add(data);
    currentblocksize += data.length();
   }                
    executor.submit(new Runnable() {                
       public void run() {
    Collections.sort(datalines,mycomparator);
    vector.add(datalines);
       }
   });

5 个答案:

答案 0 :(得分:0)

使用线程是否会加快速度取决于您是受磁盘I / O还是CPU速度限制。这取决于磁盘的速度(SSD比旋转硬盘快得多),以及比较功能的复杂程度。如果限制是磁盘I / O,则添加线程或担心数据结构没有意义,因为这些不会帮助您更快地从磁盘读取数据。如果限制是CPU速度,你应该首先运行一个探查器,以确保你的比较功能没有做任何缓慢而愚蠢的事情。

答案 1 :(得分:0)

第一个问题的答案是 - 是的。如果实现Merge Sort的并行化版本,您将获得性能提升。更多关于Dr.Dobbs的文章:http://drdobbs.com/parallel/229400239

答案 2 :(得分:0)

如果您的进程受CPU限制(我怀疑它不是),您可以看到使用多个线程的改进。如果您的进程受IO限制,则需要提高IO带宽和运行速度。

答案 3 :(得分:0)

我建议你实施以下方案,称为农场:

             worker0
reader  -->  worker1  -->  writer
             ...
             workerN

因此,一个线程从文件中读取一个块,将其交给工作线程(最佳做法是将工作者作为ExecutorService)对其进行排序,然后每个工作者将其输出发送到编写器线程放入临时文件。

编辑:好的,我查看了您的代码。要解决共享datalines的问题,您可以为每个线程创建一个私有成员,该线程存储线程需要排序的当前datalines数组:

public class ThreadTask implements Runnable {
    private List datalines = new ArrayList();

    public ThreadTask(List datalines) {
        this.datalines.add(datalines);
    }

    public void run() {
       Collections.sort(datalines,mycomparator);
       synchronized(vector) {
           vector.add(datalines); 
       }
    }
}

您还需要同步对共享vector集合的访问权限。

然后,等待ExecutorService中的所有线程完成使用:

executor.awaitTermination(30, TimeUnit.SECONDS);

答案 4 :(得分:0)

并行化顺序操作将在三种情况下提高性能:

  1. 您有一个受CPU限制的应用程序,并且有多个核心可以在没有协调的情况下工作。在这种情况下,每个核心都可以完成其工作,您将看到线性加速。但是,如果您没有多个核心,多线程实际上会让您失望。
  2. 您有一个IO绑定应用程序,您通过独立通道执行IO。应用程序服务器与多个套接字交互的情况就是这种情况。给定套接字上的数据相对不受其他套接字上发生的任何事情的阻碍。除非您可以确保磁盘操作将分离主轴并且可能分离控制器,否则通常是磁盘IO的情况。你通常不会在这里看到太多的加速,因为应用程序仍将花费大量时间等待。但是,它可以使编程模型更清晰。
  3. 您交错IO和CPU。在这种情况下,一个线程可以执行CPU密集型操作,而另一个线程在IO上等待。加速(如果有)取决于应用程序中CPU和IO之间的平衡;在许多(大多数)情况下,与IO相比,CPU贡献可以忽略不计。
  4. 您描述了案例#3,并确定了测量CPU与IO之间所需的答案。一种方法是使用分析器:如果90%的时间都在FileInputStream.read(),那么你不太可能获得加速。但是,如果50%的时间在那里,而50%在Arrays.sort(),那么你将会这样做。

    但是,我看到你的一条评论,你说你正在解析比较器内的线条。如果是这种情况,并且Arrays.sort()需要花费大量时间,那么我愿意打赌通过解析读取可以提高速度。