Как я могу улучшить производительность времени выполнения? И есть ли лучший способ прочитать этот файл? - PullRequest
0 голосов
/ 12 сентября 2018

Я пытаюсь разбить текстовый файл на несколько потоков. Файл имеет 1 ГБ. Я читаю файл по символу. Время выполнения 24 мин 54 сек. Вместо того, чтобы читать файл с помощью char, это лучший способ, с помощью которого я могу сократить время выполнения. Мне трудно найти подход, который сократит время выполнения. Пожалуйста, предложите мне также, если есть какой-либо другой лучший способ разделить файл с несколькими потоками. Я очень новичок в Java.

Любая помощь будет оценена. :)

    public static void main(String[] args) throws Exception {
        RandomAccessFile raf = new RandomAccessFile("D:\\sample\\file.txt", "r");
        long numSplits = 10;
        long sourceSize = raf.length();
        System.out.println("file length:" + sourceSize);
        long bytesPerSplit = sourceSize / numSplits;
        long remainingBytes = sourceSize % numSplits;

        int maxReadBufferSize = 9 * 1024;

        List<String> filePositionList = new ArrayList<String>();
        long startPosition = 0;
        long endPosition = bytesPerSplit;
        for (int i = 0; i < numSplits; i++) {
            raf.seek(endPosition);
            String strData = raf.readLine();
            if (strData != null) {
                endPosition = endPosition + strData.length();
            }
            String str = startPosition + "|" + endPosition;
            if (sourceSize > endPosition) {
                startPosition = endPosition;
                endPosition = startPosition + bytesPerSplit;
            } else {
                break;
            }
            filePositionList.add(str);
        }

        for (int i = 0; i < filePositionList.size(); i++) {

            String str = filePositionList.get(i);
            String[] strArr = str.split("\\|");
            String strStartPosition = strArr[0];
            String strEndPosition = strArr[1];
            long startPositionFile = Long.parseLong(strStartPosition);
            long endPositionFile = Long.parseLong(strEndPosition);
            MultithreadedSplit objMultithreadedSplit = new MultithreadedSplit(startPositionFile, endPositionFile);
            objMultithreadedSplit.start();
        }

        long endTime = System.currentTimeMillis();

        System.out.println("It took " + (endTime - startTime) + " milliseconds");
    }

}
public class MultithreadedSplit extends Thread {

    public static String filePath = "D:\\tenlakh\\file.txt";
    private int localCounter = 0;
    private long start;
    private long end;
    public static String outPath;

    List<String> result = new ArrayList<String>();

    public MultithreadedSplit(long startPos, long endPos) {
        start = startPos;
        end = endPos;
    }

    @Override
    public void run() {
        try {
            String threadName = Thread.currentThread().getName();

            long currentTime = System.currentTimeMillis();
            RandomAccessFile file = new RandomAccessFile("D:\\sample\\file.txt", "r");  
            String outFile = "out_" + threadName + ".txt";
            System.out.println("Thread Reading started for start:" + start + ";End:" + end+";threadname:"+threadName);
            FileOutputStream out2 = new FileOutputStream("D:\\sample\\" + outFile);
            file.seek(start);
            int nRecordCount = 0;

            char c = (char) file.read();
            StringBuilder objBuilder = new StringBuilder();
            int nCounter = 1;
            while (c != -1) {
                objBuilder.append(c);
                // System.out.println("char-->" + c);
                if (c == '\n') {
                    nRecordCount++;
                    out2.write(objBuilder.toString().getBytes());
                    objBuilder.delete(0, objBuilder.length());
                    //System.out.println("--->" + nRecordCount);
                    //      break;
                }
                c = (char) file.read();
                nCounter++;
                if (nCounter > end) {
                    break;
                }
            }
        } catch (Exception ex) {
           ex.printStackTrace();
        }

    }
}

1 Ответ

0 голосов
/ 12 сентября 2018

Самый быстрый способ - это отобразить файл в сегмент памяти за сегментом (отображение большого файла в целом может вызвать нежелательные побочные эффекты).Это пропустит несколько относительно дорогих операций копирования.Операционная система загрузит файл в ОЗУ, а JRE представит его вашему приложению в виде области памяти вне кучи в виде ByteBuffer.Обычно это позволяет вам сжать последние 2x / 3x производительности.

Для отображения в памяти требуется совсем немного вспомогательного кода (см. Фрагмент внизу), это не всегда лучший тактический способ.Вместо этого, если ваши входные данные основаны на строках и вам просто нужна разумная производительность (то, что у вас сейчас, вероятно, нет), просто сделайте что-то вроде:

import java.nio.Files;
import java.nio.Paths;
...
File.lines(Paths.get("/path/to/the/file"), StandardCharsets.ISO_8859_1)
//      .parallel() // parallel processing is still possible
        .forEach(line -> { /* your code goes here */ });

Для контраста, рабочий пример кода дляработа с файлом через отображение памяти будет выглядеть примерно так:В случае записей фиксированного размера (когда сегменты могут быть выбраны точно для соответствия границам записи) последующие сегменты могут обрабатываться параллельно.

static ByteBuffer mapFileSegment(FileChannel fileChannel, long fileSize, long regionOffset, long segmentSize) throws IOException {
    long regionSize = min(segmentSize, fileSize - regionOffset);

    // small last region prevention
    final long remainingSize = fileSize - (regionOffset + regionSize);
    if (remainingSize < segmentSize / 2) {
        regionSize += remainingSize;
    }

    return fileChannel.map(FileChannel.MapMode.READ_ONLY, regionOffset, regionSize);
}

...

final ToIntFunction<ByteBuffer> consumer = ...
try (FileChannel fileChannel = FileChannel.open(Paths.get("/path/to/file", StandardOpenOption.READ)) {
    final long fileSize = fileChannel.size();

    long regionOffset = 0;
    while (regionOffset < fileSize) {
        final ByteBuffer regionBuffer = mapFileSegment(fileChannel, fileSize, regionOffset, segmentSize);
        while (regionBuffer.hasRemaining()) {
            final int usedBytes = consumer.applyAsInt(regionBuffer);
            if (usedBytes == 0)
                break;
        }
        regionOffset += regionBuffer.position();
    }
} catch (IOException ex) {
    throw new UncheckedIOException(ex);
}
...