Java запись в файл производительность - PullRequest
0 голосов
/ 08 октября 2018

Я пытаюсь записать в файл с перенаправлением из командной строки.моя программа работает очень медленно, когда я читаю файл размером 25 МБ и 90% времени выполнения тратится в "System.out.println". Я пробовал некоторые другие методы, кроме System.out.print, но исправил coulnt ..

какой метод я должен использовать, чтобы напечатать большой ArrayList?(с перенаправлением)

Буду признателен за вашу помощь и пример спасибо

вот мой код:

public class Ask0 {
    public static void main(String args[]) throws IOException {
        int i = 0, token0, token1;
        String[] tokens;
        List<String> inputList = new ArrayList<>();
        Map<Integer, List<Integer>> map = new HashMap<>();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String input;

        while ((input = br.readLine()) != null) {
            tokens = input.split("\\|");
            inputList.add(tokens[0] + "|" + tokens[1]);
            token0 = Integer.parseInt(tokens[0]);
            token1 = Integer.parseInt(tokens[1]);

            List<Integer> l = map.get(token0);

            if (l == null) {
                l = new ArrayList<>();
                map.put(token0, l);
            }

            if (l.contains(token1) == false) {
                l.add(token1);
            }

            i++;
        }

        i = 0;

        for (int j = inputList.size(); j > 0; j--) {
            tokens = inputList.get(i).split("\\|");
            token0 = Integer.parseInt(tokens[0]);
            token1 = Integer.parseInt(tokens[1]);
            List l = map.get(token0);
            System.out.println(tokens[0] + "|" + tokens[1] + "[" 
                    + (l.indexOf(token1) + 1) + "," + l.size() + "]");
            i++;
        }
    }
}

Ввод

3|78 4|7765 3|82 2|8 4|14 3|78 2|8 4|12 

Желаемый результат

 3|78[1,2] 4|7765[1,3] 3|82[2,2] 2|8[1,1] 4|14[2,3] 3|78[1,2] 2|8[1,1] 4|12[3,3]

1 Ответ

0 голосов
/ 08 октября 2018

Для скорости, следующий код:

  • Использует StringBuilder для быстрой конкатенации в результирующий String и быстрый вывод, поскольку в конце печатается только один массив String, сохраняяненужные сбросы буфера.
  • Не создает группу String с при разборе ввода, только небольшие byte[] и Integer с в ArrayList.
  • Вручнуюдля чтения использует буфер размером 64 КБ.
  • Не воссоединяет токены с "|" в середине, чтобы потом снова разделить их.
  • Использует HashMap<Integer, HashMap<Integer, Integer>> вместо HashMap<Integer, ArrayList<Integer>>чтобы сэкономить время при поиске элементов в списке (алгоритм переключается с времени O (n 2 ) на время O (n)).

Некоторые ускорения могут работать не так, как выwant:

  • Не тратит время на правильную обработку Unicode.
  • Не тратит время на правильную обработку отрицательных или переполненных чисел.
  • Не важно, чтоСимволы-разделители (вы могли бы ввести "1,2,3,4,5,6" вместо этого, и он все равно работал бы так же, как "1|2\n3|4\n5|6\n").

Yoвы можете увидеть, что он дает правильные результаты для вашего тестового ввода здесь (за исключением того, что он разделяет выходные данные новыми строками, как в вашем коде).

private static final int BUFFER_SIZE = 65536;

private static enum InputState { START, MIDDLE }

public static void main(final String[] args) throws IOException {
    // Input the numbers
    final byte[] inputBuffer = new byte[BUFFER_SIZE];
    final List<Integer> inputs = new ArrayList<>();

    int inputValue = 0;
    InputState inputState = InputState.START;

    while (true) {
        int j = 0;
        final int bytesRead = System.in.read(inputBuffer, 0, BUFFER_SIZE);
        if (bytesRead == -1) {
            if (inputState == InputState.MIDDLE) {
                inputs.add(inputValue);
            }
            break;
        }

        for (int i = 0; i < bytesRead; i++) {
            byte ch = inputBuffer[i];
            int leftToken = 0;
            if (ch < 48 || ch > 57) {
                if (inputState == InputState.MIDDLE) {
                    inputs.add(inputValue);
                    inputState = InputState.START;
                }
            }
            else {
                if (inputState == InputState.START) {
                    inputValue = ch - 48;
                    inputState = InputState.MIDDLE;
                }
                else {
                    inputValue = 10*inputValue + ch - 48;
                }
            }
        }
    }
    System.in.close();

    // Put the numbers into a map
    final Map<Integer, Map<Integer, Integer>> map = new HashMap<>();

    for (int i = 0; i < inputs.size();) {
        final Integer left  = inputs.get(i++);
        final Integer right = inputs.get(i++);

        final Map<Integer, Integer> rights;
        if (map.containsKey(left)) {
            rights = map.get(left);
        }
        else {
            rights = new HashMap<>();
            map.put(left, rights);
        }

        rights.putIfAbsent(right, rights.size() + 1);
    }

    // Prepare StringBuilder with results
    final StringBuilder results = new StringBuilder();

    for (int i = 0; i < inputs.size();) {
        final Integer left  = inputs.get(i++);
        final Integer right = inputs.get(i++);

        final Map<Integer, Integer> rights = map.get(left);

        results.append(left).append('|').append(right);
        results.append('[').append(rights.get(right)).append(',');
        results.append(rights.size()).append(']').append('\n');
    }

    System.out.print(results);
}

Вы также можете использовать вручную64 КБ byte[] выходной буфер также с System.out.write(outputBuffer, 0, bytesToWrite); System.out.flush();, если вы хотите сэкономить память, хотя это намного больше работы.

Кроме того, если вы знаете минимальные и максимальные значения, которые вы увидите, выможно использовать массивы int[] или int[][] вместо Map<Integer, Integer> или Map<Integer, Map<Integer, Integer>>, хотя это также несколько сложнее.Хотя это было бы очень быстро.

...