外部排序优化

优化外部排序
主要步骤重新拆分如下
第一阶段
1.将未排序的大文件切分(spilterReceiver)
2.一个线程池专门接收byte[],并将其转化为long[] (prepareReceiver)
3.一个线程池专门排序long[] (sortReceiver)
4.一个线程池专门将已经有序的long[]写入文件 (writerReceiver)

这个过程直接写long类型的数字到文件,因为写入文本占用IO资源比直接写入long型数字要多。

第二阶段
1.一个线程用于归并排序,将结果写入缓冲区 (mergerReceiver)
2.如果缓冲区快满了,就将其交给一个线程池用于写入最终的文件。 (mergerReceiver)

优化的重点是平衡CPU,内存和硬盘的资源使用。

每个电脑的配置不同,都需要进行不同的调整,才能达到最优化的效果。
单位的电脑是i5的CPU,8G内存,7200转硬盘。
我使用的虚拟机分配了2个核心,4G内存。
跑这个程序大致需要200s左右。
因为第二阶段的第一个步骤是非常消耗CPU资源的,单位电脑CPU主频很高,所以不会成为瓶颈。

而家里的电脑,应该配置更接近吴老师做实验的配置。主频比较低,32位系统,4G内存。
这个配置明显CPU成为瓶颈
在第一个阶段,切分出来的文件,由于CPU不能及时排序并输出,经常导致OOM
只能在切分一个文件出来之后,让切分线程sleep一段时间,大量测试得到的结果是这个线程至少sleep2500毫秒才能不导致OOM。
也就是说,CPU运算的速度跟不上IO的速度。后来想到一个方法,加大分片。原来4G文件使用15个分片,现在使用30个分片。数据快入快出,这样可以避免OOM。至于这个分片的数字,恐怕每个机器都需要实际的测试。
另外在第二阶段,也出现了CPU拖累IO,导致性能下降。
因为归并的时候,需要大量运算各个分片中最小的数据,经常看到计算50M数据,CPU需要2s,而写入一般1s就可以完成。
而这个过程是单线程的,CPU的主频直接决定了外部排序的总体时间。


import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Controller {
    public static void main(String[] args) throws IOException {
        new Controller().action(new File("/home/lihuilin/桌面/t.txt"), 30, "/home/lihuilin/桌面/");

    }

    public void action(File file, int pieces, String outDir) throws IOException {
        Invoker invoker = new Invoker(pieces);
        List<Command> commandList = blocking(file, pieces, outDir);
        for (Command command : commandList) {
            command.setInvoker(invoker);
            invoker.executeCommand(command);
        }
    }

    private List<Command> blocking(File file, int pieces, String outDir) throws IOException {
        List<Command> result = new ArrayList<Command>();
        List<Long> list = new ArrayList<Long>();
        list.add(-1L);
        long length = file.length();
        long step = length / pieces;
        long index = 0;
        for (int i = 0; i < pieces; i++) {
            BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
            if (index + step < length) {
                index = index + step;
                in.skip(index);
                while (in.read() != 10) {
                    index = index + 1;
                }
                list.add(index);
                index++;
            }
            in.close();
        }
        list.add(length - 1);
        for (int i = 0; i < list.size() - 1; i++) {
            long skipSize = list.get(i) + 1;
            long l = list.get(i + 1) - list.get(i);
            result.add(new SpilterCommand(file, skipSize, l, outDir));
        }
        return result;
    }

}

interface Command extends Comparable<Command> {
    public void setInvoker(Invoker invoker);

    public void setReceiver(Receiver receiver);

    public void execute() throws IOException;

    public long getSkipSize();

    public int getLength();

    public String getOutDir();

    public File getSourceFile();

    public Invoker getInvoker();

    public void clear();

    public File getOutFile();

    public File getTargetFile();
}

class Invoker {
    private Receiver sortReceiver;
    private Receiver spilterReceiver;
    private Receiver writerReceiver;
    private Receiver prepareReceiver;
    private Receiver mergerReceiver;

    public Invoker(int pieces) {
        writerReceiver = new WriterReceiver(pieces);
        spilterReceiver = new SpilterReceiver();
        sortReceiver = new SorterReceiver();
        prepareReceiver = new PrepareReceiver();
        mergerReceiver = new MergerReceiver();
    }

    public void executeCommand(Command command) {
        try {
            if (command instanceof SpilterCommand) {
                spilterReceiver.action(command);
            } else if (command instanceof PrepareCommand) {
                prepareReceiver.action(command);
            } else if (command instanceof SortCommand) {
                sortReceiver.action(command);
            } else if (command instanceof WriterCommand) {
                writerReceiver.action(command);
            } else if (command instanceof MergeCommand) {
                mergerReceiver.action(command);
            } else if (command instanceof KillCommand) {
                writerReceiver.shutdown();
                spilterReceiver.shutdown();
                sortReceiver.shutdown();
                prepareReceiver.shutdown();
                mergerReceiver.shutdown();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

class SpilterCommand extends AbstractCommand {

    public SpilterCommand(File sourceFile, long skipSize, long length, String outDir) {
        super(sourceFile, skipSize, length, outDir);
    }

    @Override
    public void clear() {

    }

}

abstract class AbstractCommand implements Command {
    private Invoker invoker = null;
    private Receiver receiver = null;
    private long skipSize = 0L;
    private int length = 0;
    private String outDir = null;
    private File sourceFile;
    private File outFile = null;
    public static final long START = System.currentTimeMillis();
    private static int FLAG = 0;
    private File targetFile = null;

    private synchronized int getFlag() {
        return FLAG++;
    }

    public AbstractCommand(Command command) {
        this(command.getSourceFile(), command.getSkipSize(), command.getLength(), command.getOutDir());
        this.invoker = command.getInvoker();
        if (command.getOutFile() != null) {
            this.outFile = command.getOutFile();
        } else {
            this.outFile = new File(this.outDir + getFlag() + ".temp");
        }
    }

    public AbstractCommand(File sourceFile, long skipSize, long length, String outDir) {
        if (length > Integer.MAX_VALUE) {
            throw new RuntimeException("长度溢出");
        }
        this.skipSize = skipSize;
        this.length = (int) length;
        this.outDir = outDir;
        this.sourceFile = sourceFile;
        this.targetFile = new File(outDir + "result.temp");
    }

    public void setInvoker(Invoker invoker) {
        this.invoker = invoker;
    }

    public void setReceiver(Receiver receiver) {
        this.receiver = receiver;
    }

    public long getSkipSize() {
        return skipSize;
    }

    public int getLength() {
        return length;
    }

    public String getOutDir() {
        return outDir;
    }

    public File getSourceFile() {
        return sourceFile;
    }

    @Override
    public String toString() {
        return "Command [skipSize=" + skipSize + ", length=" + length + "]";
    }

    public void execute() throws IOException {
        this.receiver.action(this);
    }

    public Invoker getInvoker() {
        return invoker;
    }

    public File getOutFile() {
        return this.outFile;
    }

    public File getTargetFile() {
        return this.targetFile;
    }

    @Override
    public int compareTo(Command o) {
        if (this.skipSize < o.getSkipSize()) {
            return -1;
        }
        return 1;
    }
}

interface Receiver {
    public void action(Command command) throws IOException;

    public void shutdown();
}

class PrepareReceiver implements Receiver {
    private ExecutorService prepareThreadPool;

    public PrepareReceiver() {
        prepareThreadPool = Executors.newFixedThreadPool(4);
    }

    @Override
    public void action(final Command command) throws IOException {
        prepareThreadPool.submit(new Runnable() {

            @Override
            public void run() {
                System.out.println("\t整理数据:" + command);
                long start = System.currentTimeMillis();

                byte[] data = ((PrepareCommand) command).getData();
                long[] result = new long[getObjectSize(data)];
                int resultIndex = 0;
                int index = 0;
                int first = 0;
                while (index < data.length) {
                    if (data[index] == 10) {
                        byte[] tmpData = Arrays.copyOfRange(data, first, index);
                        String str = new String(tmpData);
                        result[resultIndex] = Long.valueOf(str);
                        resultIndex++;
                        first = index + 1;
                    }

                    index++;
                }
                command.getInvoker().executeCommand(new SortCommand(command, result));

                result = null;
                data = null;
                command.clear();

                long end = System.currentTimeMillis();
                System.out.println("\t结束整理数据:" + command + ",用时:" + (end - start) / 1000);
            }

        });

    }

    private int getObjectSize(byte[] data) {
        int size = 0;
        for (byte b : data) {
            if (b == 10) {
                size++;
            }
        }
        return size;
    }

    @Override
    public void shutdown() {
        this.prepareThreadPool.shutdown();
    }

}

class PrepareCommand extends AbstractCommand {

    private byte[] data;

    public PrepareCommand(Command command, byte[] data) {
        super(command);
        this.data = data;
    }

    public byte[] getData() {
        return this.data;
    }

    @Override
    public void clear() {
        this.data = null;
    }
}

class SpilterReceiver implements Receiver {
    @Override
    public void action(final Command command) throws IOException {
        try {
            System.out.println("开始读入:" + command);
            long start = System.currentTimeMillis();
            FileChannel in = new RandomAccessFile(command.getSourceFile(), "r").getChannel();
            MappedByteBuffer inBuffer = in.map(MapMode.READ_ONLY, command.getSkipSize(), command.getLength());
            byte[] data = new byte[inBuffer.limit()];
            inBuffer.get(data);
            command.getInvoker().executeCommand(new PrepareCommand(command, data));

            data = null;
            in.close();
            command.clear();

            long end = System.currentTimeMillis();
            System.out.println("结束内存读入:" + (end - start) / 1000 + "s");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void shutdown() {
    }
}

class MergeCommand extends AbstractCommand {
    private List<Command> commandList = null;

    public MergeCommand(List<Command> commandList) {
        super(commandList.get(0));
        this.commandList = commandList;
    }

    @Override
    public void clear() {

    }

    public List<Command> getCommandList() {
        return this.commandList;
    }
}

class KillCommand extends AbstractCommand {

    public KillCommand(Command command) {
        super(command);
    }

    @Override
    public void clear() {

    }

}

class MergerReceiver implements Receiver {
    private ExecutorService mergerThreadPool = Executors.newFixedThreadPool(4);
    private List<Worker> workerList = new ArrayList<Worker>();
    private ByteBuffer bb = null;

    @Override
    public void action(final Command command) throws IOException {
        bb = ByteBuffer.allocate(50 * 1024 * 1024);
        List<Command> list = ((MergeCommand) command).getCommandList();
        for (Command historyCommand : list) {
            Worker worker = new Worker(historyCommand.getOutFile(), workerList);
            workerList.add(worker);
        }

        System.out.println("读取队列,写入目标文件");
        long start = System.currentTimeMillis();
        RandomAccessFile targetFile = new RandomAccessFile(command.getTargetFile(), "rw");
        FileChannel channel = targetFile.getChannel();
        MappedByteBuffer out = null;
        long index = 0L;
        while (workerList.size() != 0) {
            Worker worker = Collections.min(workerList);
            Long data = worker.poll();
            if (data == null) {
                workerList.remove(worker);
            } else {

                bb.put((data + "\n").getBytes());

                if (bb.position() > 49 * 1024 * 1024) {
                    long end = System.currentTimeMillis();
                    System.out.println("归并用时:" + (end - start)/1000 + "s");
                    start = System.currentTimeMillis();
                    bb.flip();
                    long temp = bb.limit();
                    MutiWriter writer = new MutiWriter(channel, bb, index);
                    mergerThreadPool.submit(writer);
                    index = index + temp;
                    bb = ByteBuffer.allocate(50 * 1024 * 1024);
                }

            }
        }

        bb.flip();

        out = channel.map(MapMode.READ_WRITE, index, bb.limit());
        int i = bb.limit();
        while (i > .0) {
            out.put(bb.get());
            i--;
        }
        out.force();
        channel.close();
        targetFile.close();

        KillCommand killCommand = new KillCommand(command);
        command.getInvoker().executeCommand(killCommand);

        long end = System.currentTimeMillis();
        System.out.println("外部排序总用时:" + (end - AbstractCommand.START) / 1000);

    }

    private class MutiWriter implements Runnable {
        private ByteBuffer buffer;
        private MappedByteBuffer out = null;

        public MutiWriter(FileChannel channel, ByteBuffer buffer, long index) {
            this.buffer = buffer;
            try {
                out = channel.map(MapMode.READ_WRITE, index, buffer.limit());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            long a1 = System.currentTimeMillis();
            int i = buffer.limit();
            while (i > 0) {
                out.put(buffer.get());
                i--;
            }
            out.force();
            out = null;
            long a2 = System.currentTimeMillis();
            System.out.println("内存映射写入:" + (a2 - a1) / 1000 + "s");
        }

    }

    @Override
    public void shutdown() {
        mergerThreadPool.shutdown();
    }

    private class Worker implements Comparable<Worker> {
        private long data;
        private MappedByteBuffer buffer = null;
        private List<Worker> workerList = null;
        private boolean eof = false;

        Worker(File file, List<Worker> workerList) {
            try {
                RandomAccessFile rFile = new RandomAccessFile(file, "r");
                FileChannel channel = rFile.getChannel();
                buffer = channel.map(MapMode.READ_ONLY, 0, channel.size());

                this.workerList = workerList;
                data = buffer.getLong();

                rFile.close();
                channel.close();

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        public long peek() {
            return data;
        }

        public Long poll() {
            long result = data;
            if (buffer.position() != buffer.limit()) {
                data = buffer.getLong();
            } else {
                if (eof == false) {
                    eof = true;
                } else {
                    return null;
                }
            }

            return result;
        }

        @Override
        public int compareTo(Worker o) {
            if (this.peek() > o.peek()) {
                return 1;
            } else if (this.peek() < o.peek()) {
                return -1;
            } else {
                return 0;
            }
        }
    }

}

class WriterReceiver implements Receiver {
    private ExecutorService writeThreadPool = null;;
    private CyclicBarrier barrier = null;
    private List<Command> commandList = new ArrayList<Command>();

    public WriterReceiver(int pieces) {
        writeThreadPool = Executors.newFixedThreadPool(pieces + 2);
        barrier = new CyclicBarrier(pieces, new Runnable() {

            @Override
            public void run() {
                long end = System.currentTimeMillis();
                System.out.println("合并之前总用时:" + (end - AbstractCommand.START) / 1000);

                MergeCommand command = new MergeCommand(WriterReceiver.this.commandList);
                command.getInvoker().executeCommand(command);

            }
        });

    }

    @Override
    public void action(final Command command) {
        writeThreadPool.submit(new Runnable() {

            @Override
            public void run() {
                long[] data = ((WriterCommand) command).getData();

                try {
                    System.out.println("\t\t\t开始写入:" + command);
                    long start = System.currentTimeMillis();
                    File outfile = command.getOutFile();
                    FileChannel channel = new RandomAccessFile(outfile, "rw").getChannel();
                    MappedByteBuffer buffer = channel.map(MapMode.READ_WRITE, 0, data.length * 8);
                    for (int i = 0; i < data.length; i++) {
                        buffer.putLong(data[i]);
                    }
                    buffer.force();
                    WriterReceiver.this.commandList.add(command);
                    long end = System.currentTimeMillis();
                    System.out.println("\t\t\t结束写入:" + command + ",用时:" + (end - start) / 1000);

                    command.clear();
                    data = null;
                    channel.close();
                    buffer = null;

                    barrier.await();
                } catch (IOException ex) {
                    ex.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    public void shutdown() {
        writeThreadPool.shutdown();
    }
}

class SortCommand extends AbstractCommand {
    private long[] data = null;

    public SortCommand(Command command, long[] data) {
        super(command);
        this.data = data;
    }

    public long[] getData() {
        return this.data;
    }

    @Override
    public void clear() {
        this.data = null;
    }

}

class SorterReceiver implements Receiver {
    private ExecutorService sortThreadPool = Executors.newFixedThreadPool(4);

    public void action(final Command command) {
        sortThreadPool.submit(new Runnable() {

            @Override
            public void run() {
                System.out.println("\t\t开始排序:" + command);
                long start = System.currentTimeMillis();

                long[] data = ((SortCommand) command).getData();
                Arrays.sort(data);

                command.getInvoker().executeCommand(new WriterCommand(command, data));

                data = null;
                command.clear();

                long end = System.currentTimeMillis();
                System.out.println("\t\t结束排序:" + command + ",用时:" + (end - start) / 1000);

            }

        });

    }

    @Override
    public void shutdown() {
        sortThreadPool.shutdown();
    }
}

class WriterCommand extends AbstractCommand {
    private long[] data;

    public WriterCommand(Command command, long[] data) {
        super(command);
        this.data = data;
    }

    public long[] getData() {
        return this.data;
    }

    @Override
    public void clear() {
        this.data = null;
    }

}
最近真的很忙,我这一个单线程的CPU居然都跑出了双核的感觉。
我感觉优化就是找到慢的地方,看看是不是有无效的操作,如果都是有效运算,就只能想办法使用多线程,使压力分散在多个核心上。
之前吴老师说他用的是直接缓冲区+通道 IO的方式。自己写程序将long直接转化为byte。
这个优化的方式我试了一下,不能应用在我的场景。
他的本意是减少GC,但是在我的场景,这种方式更加剧了CPU的争用。
优化的本质应该是平衡资源

程序日志,相比最初的版本,性能提升了50s
因为将切分文件,byte数组转为long数组拆分为了两个操作,并且使用了多线程处理。
开始读入:Command [skipSize=0, length=135863265] 结束内存读入:3s 整理数据:Command [skipSize=0, length=135863265] 开始读入:Command [skipSize=135863265, length=135863254] 结束整理数据:Command [skipSize=0, length=135863265],用时:4 开始排序:Command [skipSize=0, length=135863265] 结束内存读入:4s 开始读入:Command [skipSize=271726519, length=135863267] 整理数据:Command [skipSize=135863265, length=135863254] 结束排序:Command [skipSize=0, length=135863265],用时:2 开始写入:Command [skipSize=0, length=135863265] 结束内存读入:3s 开始读入:Command [skipSize=407589786, length=135863268] 整理数据:Command [skipSize=271726519, length=135863267] 结束写入:Command [skipSize=0, length=135863265],用时:2 结束整理数据:Command [skipSize=135863265, length=135863254],用时:5 开始排序:Command [skipSize=135863265, length=135863254] 结束排序:Command [skipSize=135863265, length=135863254],用时:1 开始写入:Command [skipSize=135863265, length=135863254] 结束整理数据:Command [skipSize=271726519, length=135863267],用时:4 开始排序:Command [skipSize=271726519, length=135863267] 结束排序:Command [skipSize=271726519, length=135863267],用时:1 开始写入:Command [skipSize=271726519, length=135863267] 结束写入:Command [skipSize=135863265, length=135863254],用时:6 结束写入:Command [skipSize=271726519, length=135863267],用时:4 结束内存读入:11s 整理数据:Command [skipSize=407589786, length=135863268] 开始读入:Command [skipSize=543453054, length=135863264] 结束整理数据:Command [skipSize=407589786, length=135863268],用时:3 开始排序:Command [skipSize=407589786, length=135863268] 结束内存读入:4s 开始读入:Command [skipSize=679316318, length=135863268] 整理数据:Command [skipSize=543453054, length=135863264] 结束排序:Command [skipSize=407589786, length=135863268],用时:1 开始写入:Command [skipSize=407589786, length=135863268] 结束写入:Command [skipSize=407589786, length=135863268],用时:1 结束整理数据:Command [skipSize=543453054, length=135863264],用时:3 开始排序:Command [skipSize=543453054, length=135863264] 结束排序:Command [skipSize=543453054, length=135863264],用时:1 开始写入:Command [skipSize=543453054, length=135863264] 结束写入:Command [skipSize=543453054, length=135863264],用时:1 结束内存读入:7s 整理数据:Command [skipSize=679316318, length=135863268] 开始读入:Command [skipSize=815179586, length=135863264] 结束内存读入:3s 开始读入:Command [skipSize=951042850, length=135863270] 整理数据:Command [skipSize=815179586, length=135863264] 开始排序:Command [skipSize=679316318, length=135863268] 结束整理数据:Command [skipSize=679316318, length=135863268],用时:3 结束排序:Command [skipSize=679316318, length=135863268],用时:2 开始写入:Command [skipSize=679316318, length=135863268] 结束整理数据:Command [skipSize=815179586, length=135863264],用时:4 开始排序:Command [skipSize=815179586, length=135863264] 结束写入:Command [skipSize=679316318, length=135863268],用时:2 结束内存读入:5s 整理数据:Command [skipSize=951042850, length=135863270] 开始读入:Command [skipSize=1086906120, length=135863262] 结束排序:Command [skipSize=815179586, length=135863264],用时:1 开始写入:Command [skipSize=815179586, length=135863264] 结束写入:Command [skipSize=815179586, length=135863264],用时:1 整理数据:Command [skipSize=1086906120, length=135863262] 结束内存读入:3s 开始读入:Command [skipSize=1222769382, length=135863265] 开始排序:Command [skipSize=951042850, length=135863270] 结束整理数据:Command [skipSize=951042850, length=135863270],用时:4 结束内存读入:3s 开始读入:Command [skipSize=1358632647, length=135863256] 整理数据:Command [skipSize=1222769382, length=135863265] 结束排序:Command [skipSize=951042850, length=135863270],用时:2 开始写入:Command [skipSize=951042850, length=135863270] 结束写入:Command [skipSize=951042850, length=135863270],用时:1 结束整理数据:Command [skipSize=1086906120, length=135863262],用时:5 开始排序:Command [skipSize=1086906120, length=135863262] 结束排序:Command [skipSize=1086906120, length=135863262],用时:1 开始写入:Command [skipSize=1086906120, length=135863262] 结束内存读入:4s 整理数据:Command [skipSize=1358632647, length=135863256] 开始读入:Command [skipSize=1494495903, length=135863268] 结束写入:Command [skipSize=1086906120, length=135863262],用时:1 开始排序:Command [skipSize=1222769382, length=135863265] 结束整理数据:Command [skipSize=1222769382, length=135863265],用时:6 结束排序:Command [skipSize=1222769382, length=135863265],用时:1 开始写入:Command [skipSize=1222769382, length=135863265] 整理数据:Command [skipSize=1494495903, length=135863268] 结束内存读入:4s 开始读入:Command [skipSize=1630359171, length=135863255] 开始排序:Command [skipSize=1358632647, length=135863256] 结束整理数据:Command [skipSize=1358632647, length=135863256],用时:5 结束写入:Command [skipSize=1222769382, length=135863265],用时:1 结束排序:Command [skipSize=1358632647, length=135863256],用时:1 开始写入:Command [skipSize=1358632647, length=135863256] 结束整理数据:Command [skipSize=1494495903, length=135863268],用时:3 结束写入:Command [skipSize=1358632647, length=135863256],用时:2 开始排序:Command [skipSize=1494495903, length=135863268] 结束内存读入:4s 整理数据:Command [skipSize=1630359171, length=135863255] 开始读入:Command [skipSize=1766222426, length=135863271] 结束排序:Command [skipSize=1494495903, length=135863268],用时:1 开始写入:Command [skipSize=1494495903, length=135863268] 结束写入:Command [skipSize=1494495903, length=135863268],用时:1 结束整理数据:Command [skipSize=1630359171, length=135863255],用时:3 开始排序:Command [skipSize=1630359171, length=135863255] 整理数据:Command [skipSize=1766222426, length=135863271] 结束内存读入:4s 开始读入:Command [skipSize=1902085697, length=135863258] 结束排序:Command [skipSize=1630359171, length=135863255],用时:2 开始写入:Command [skipSize=1630359171, length=135863255] 结束写入:Command [skipSize=1630359171, length=135863255],用时:1 结束整理数据:Command [skipSize=1766222426, length=135863271],用时:3 开始排序:Command [skipSize=1766222426, length=135863271] 整理数据:Command [skipSize=1902085697, length=135863258] 结束内存读入:4s 开始读入:Command [skipSize=2037948955, length=135863254] 结束排序:Command [skipSize=1766222426, length=135863271],用时:1 开始写入:Command [skipSize=1766222426, length=135863271] 结束写入:Command [skipSize=1766222426, length=135863271],用时:1 结束整理数据:Command [skipSize=1902085697, length=135863258],用时:3 开始排序:Command [skipSize=1902085697, length=135863258] 整理数据:Command [skipSize=2037948955, length=135863254] 结束内存读入:4s 开始读入:Command [skipSize=2173812209, length=135863259] 结束排序:Command [skipSize=1902085697, length=135863258],用时:2 开始写入:Command [skipSize=1902085697, length=135863258] 结束写入:Command [skipSize=1902085697, length=135863258],用时:1 结束整理数据:Command [skipSize=2037948955, length=135863254],用时:3 开始排序:Command [skipSize=2037948955, length=135863254] 结束内存读入:4s 整理数据:Command [skipSize=2173812209, length=135863259] 开始读入:Command [skipSize=2309675468, length=135863260] 结束排序:Command [skipSize=2037948955, length=135863254],用时:2 开始写入:Command [skipSize=2037948955, length=135863254] 结束整理数据:Command [skipSize=2173812209, length=135863259],用时:3 开始排序:Command [skipSize=2173812209, length=135863259] 结束内存读入:4s 整理数据:Command [skipSize=2309675468, length=135863260] 开始读入:Command [skipSize=2445538728, length=135863266] 结束写入:Command [skipSize=2037948955, length=135863254],用时:2 结束排序:Command [skipSize=2173812209, length=135863259],用时:2 开始写入:Command [skipSize=2173812209, length=135863259] 结束写入:Command [skipSize=2173812209, length=135863259],用时:1 结束整理数据:Command [skipSize=2309675468, length=135863260],用时:3 开始排序:Command [skipSize=2309675468, length=135863260] 整理数据:Command [skipSize=2445538728, length=135863266] 结束内存读入:4s 开始读入:Command [skipSize=2581401994, length=135863268] 结束排序:Command [skipSize=2309675468, length=135863260],用时:2 开始写入:Command [skipSize=2309675468, length=135863260] 结束写入:Command [skipSize=2309675468, length=135863260],用时:1 结束整理数据:Command [skipSize=2445538728, length=135863266],用时:4 开始排序:Command [skipSize=2445538728, length=135863266] 结束内存读入:4s 整理数据:Command [skipSize=2581401994, length=135863268] 开始读入:Command [skipSize=2717265262, length=135863264] 结束排序:Command [skipSize=2445538728, length=135863266],用时:2 开始写入:Command [skipSize=2445538728, length=135863266] 结束写入:Command [skipSize=2445538728, length=135863266],用时:1 结束整理数据:Command [skipSize=2581401994, length=135863268],用时:3 开始排序:Command [skipSize=2581401994, length=135863268] 整理数据:Command [skipSize=2717265262, length=135863264] 结束内存读入:4s 开始读入:Command [skipSize=2853128526, length=135863258] 结束排序:Command [skipSize=2581401994, length=135863268],用时:2 开始写入:Command [skipSize=2581401994, length=135863268] 结束写入:Command [skipSize=2581401994, length=135863268],用时:1 结束整理数据:Command [skipSize=2717265262, length=135863264],用时:3 开始排序:Command [skipSize=2717265262, length=135863264] 整理数据:Command [skipSize=2853128526, length=135863258] 结束内存读入:4s 开始读入:Command [skipSize=2988991784, length=135863254] 结束排序:Command [skipSize=2717265262, length=135863264],用时:2 开始写入:Command [skipSize=2717265262, length=135863264] 结束写入:Command [skipSize=2717265262, length=135863264],用时:1 结束整理数据:Command [skipSize=2853128526, length=135863258],用时:3 开始排序:Command [skipSize=2853128526, length=135863258] 结束内存读入:4s 整理数据:Command [skipSize=2988991784, length=135863254] 开始读入:Command [skipSize=3124855038, length=135863260] 结束排序:Command [skipSize=2853128526, length=135863258],用时:2 开始写入:Command [skipSize=2853128526, length=135863258] 结束写入:Command [skipSize=2853128526, length=135863258],用时:1 结束整理数据:Command [skipSize=2988991784, length=135863254],用时:3 开始排序:Command [skipSize=2988991784, length=135863254] 整理数据:Command [skipSize=3124855038, length=135863260] 结束内存读入:4s 开始读入:Command [skipSize=3260718298, length=135863254] 结束排序:Command [skipSize=2988991784, length=135863254],用时:2 开始写入:Command [skipSize=2988991784, length=135863254] 结束写入:Command [skipSize=2988991784, length=135863254],用时:2 结束整理数据:Command [skipSize=3124855038, length=135863260],用时:4 开始排序:Command [skipSize=3124855038, length=135863260] 整理数据:Command [skipSize=3260718298, length=135863254] 结束内存读入:4s 开始读入:Command [skipSize=3396581552, length=135863262] 结束排序:Command [skipSize=3124855038, length=135863260],用时:1 开始写入:Command [skipSize=3124855038, length=135863260] 结束写入:Command [skipSize=3124855038, length=135863260],用时:2 结束整理数据:Command [skipSize=3260718298, length=135863254],用时:3 开始排序:Command [skipSize=3260718298, length=135863254] 结束内存读入:4s 整理数据:Command [skipSize=3396581552, length=135863262] 开始读入:Command [skipSize=3532444814, length=135863265] 结束排序:Command [skipSize=3260718298, length=135863254],用时:1 开始写入:Command [skipSize=3260718298, length=135863254] 结束写入:Command [skipSize=3260718298, length=135863254],用时:2 结束整理数据:Command [skipSize=3396581552, length=135863262],用时:3 开始排序:Command [skipSize=3396581552, length=135863262] 结束内存读入:4s 整理数据:Command [skipSize=3532444814, length=135863265] 开始读入:Command [skipSize=3668308079, length=135863273] 结束排序:Command [skipSize=3396581552, length=135863262],用时:2 开始写入:Command [skipSize=3396581552, length=135863262] 结束写入:Command [skipSize=3396581552, length=135863262],用时:2 结束整理数据:Command [skipSize=3532444814, length=135863265],用时:3 开始排序:Command [skipSize=3532444814, length=135863265] 结束内存读入:4s 整理数据:Command [skipSize=3668308079, length=135863273] 开始读入:Command [skipSize=3804171352, length=135863261] 结束排序:Command [skipSize=3532444814, length=135863265],用时:2 开始写入:Command [skipSize=3532444814, length=135863265] 结束写入:Command [skipSize=3532444814, length=135863265],用时:1 结束整理数据:Command [skipSize=3668308079, length=135863273],用时:3 开始排序:Command [skipSize=3668308079, length=135863273] 整理数据:Command [skipSize=3804171352, length=135863261] 结束内存读入:4s 开始读入:Command [skipSize=3940034613, length=135862991] 结束排序:Command [skipSize=3668308079, length=135863273],用时:2 开始写入:Command [skipSize=3668308079, length=135863273] 结束写入:Command [skipSize=3668308079, length=135863273],用时:2 结束整理数据:Command [skipSize=3804171352, length=135863261],用时:3 开始排序:Command [skipSize=3804171352, length=135863261] 结束内存读入:4s 整理数据:Command [skipSize=3940034613, length=135862991] 结束排序:Command [skipSize=3804171352, length=135863261],用时:1 开始写入:Command [skipSize=3804171352, length=135863261] 结束写入:Command [skipSize=3804171352, length=135863261],用时:1 结束整理数据:Command [skipSize=3940034613, length=135862991],用时:3 开始排序:Command [skipSize=3940034613, length=135862991] 结束排序:Command [skipSize=3940034613, length=135862991],用时:1 开始写入:Command [skipSize=3940034613, length=135862991] 结束写入:Command [skipSize=3940034613, length=135862991],用时:1 合并之前总用时:143 读取队列,写入目标文件 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:1s 归并用时:2s 归并用时:1s 内存映射写入:3s 归并用时:2s 归并用时:2s 内存映射写入:5s 内存映射写入:3s 归并用时:2s 内存映射写入:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 归并用时:2s 内存映射写入:2s 内存映射写入:1s 归并用时:2s 归并用时:2s 内存映射写入:2s 内存映射写入:2s 归并用时:2s 归并用时:2s 内存映射写入:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 归并用时:2s 内存映射写入:2s 内存映射写入:2s 归并用时:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 归并用时:2s 内存映射写入:4s 内存映射写入:2s 归并用时:3s 内存映射写入:2s 归并用时:2s 归并用时:2s 内存映射写入:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 归并用时:1s 归并用时:2s 归并用时:4s 内存映射写入:6s 内存映射写入:8s 内存映射写入:4s 归并用时:2s 归并用时:2s 内存映射写入:3s 内存映射写入:5s 内存映射写入:2s 归并用时:3s 归并用时:2s 内存映射写入:2s 内存映射写入:2s 归并用时:2s 内存映射写入:1s 归并用时:3s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 内存映射写入:2s 归并用时:2s 归并用时:2s 内存映射写入:2s 内存映射写入:2s 归并用时:2s 内存映射写入:1s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:2s 归并用时:2s 内存映射写入:1s 外部排序总用时:351

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29254281/viewspace-1172752/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/29254281/viewspace-1172752/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值