@dezzus

Java. Тест производительности?

Задание: https://devtest1.hr.bookmap.com/task
Написал код, алгоритм работает правильно, но тест производительности не проходит:
" Error
Your solution produced the correct output but failed the performance test.
Please, note that using too much memory can sometimes result in a timeout due to GC overhead - in other words, this timeout might actually be an OutOfMemoryError. This error might also occur due to wrong data produced during the performance test."

Выдайте, пожалуйста, замечания.
Код:
package javaapplicationmy;
 
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.FileWriter;
import java.io.FileReader;
import java.util.ArrayList;

public class JavaApplicationMy {

    private ArrayList<Integer> bid_price = new ArrayList();
    private ArrayList<Integer> ask_price = new ArrayList();
    private ArrayList<Integer> bid_size = new ArrayList();
    private ArrayList<Integer> ask_size = new ArrayList(); 

    public static void main(String[] args) throws IOException {
        JavaApplicationMy my = new JavaApplicationMy();
        String str, strng;
        String[] words;
        my.bid_price.clear();
        my.ask_price.clear();
        my.bid_size.clear();
        my.ask_size.clear();
        String fileName = "input.txt";
        String outputFileName = "output.txt";
        //String fileName = "d:\\input.txt";
        //String outputFileName = "d:\\output.txt";
        try (BufferedReader reader = new BufferedReader(new FileReader(fileName)); BufferedWriter writter = new BufferedWriter(new FileWriter(outputFileName))) {
            while (((strng = reader.readLine()) != null)) {
                words = strng.split(",");            
                char ch = words[0].charAt(0);
                switch (ch) {
                    case 'u' -> {
                        if (words[3].compareTo("bid") == 0) {
                            my.bids(Integer.parseInt(words[1]), Integer.parseInt(words[2]));
                        }
                        else if (words[3].compareTo("ask") == 0) {
                            my.asks(Integer.parseInt(words[1]), Integer.parseInt(words[2]));
                        }
                    }
                    case 'q' -> {
                        if (words[1].compareTo("best_bid") == 0 && !my.bid_size.isEmpty()) {
                            str = String.join("", my.bid_price.get(0).toString(), ",", my.bid_size.get(0).toString(), "\n");
                            writter.write(str);
                        }
                        else if (words[1].compareTo("best_ask") == 0 && !my.ask_size.isEmpty()) {
                            str = String.join("", my.ask_price.get(0).toString(), ",", my.ask_size.get(0).toString(), "\n");
                            writter.write(str);
                        }
                        else if (words[1].compareTo("size") == 0) {
                            int size = my.find_size(Integer.parseInt(words[2]));
                            writter.write(String.join("", Integer.toString(size), "\n"));
                        }
                    }
                    case 'o' -> {
                        if (words[1].compareTo("buy") == 0) {
                            my.buy(Integer.parseInt(words[2]));
                        }
                        else if (words[1].compareTo("sell") == 0) {
                            my.sell(Integer.parseInt(words[2]));
                        }
                    }
                }                
            }
        }catch(IOException e){
           throw new RuntimeException(e);
        }
    }
    
    public void bids(int price, int size) throws IOException {
        boolean flag;
        flag = false;
        if (bid_price.isEmpty() && size > 0) {
            bid_price.add(price);
            bid_size.add(size);
        }
        else {
            for (int i = 0, n = bid_price.size(); i < n; i++) {
                if (price >= bid_price.get(i)) {
                    flag = true;
                    if (price == bid_price.get(i)) {
                        bid_size.set(i, size);        
                    }
                    else {
                        bid_price.add(i, price);
                        bid_size.add(i, size);  
                    }
                    if (i==0 && size == 0) {
                        bid_price.remove(0);
                        bid_size.remove(0); 
                    }
                    break;
                }            
            }
            if (flag == false && size > 0) {
               bid_price.add(price);
               bid_size.add(size); 
            }
        }
    }
    
    public void asks(int price, int size) throws IOException {
        boolean flag;
        flag = false;
        if (ask_price.isEmpty() && size > 0) {
            ask_price.add(price);
            ask_size.add(size);
        }
        else {
            for (int i = 0, n = ask_price.size(); i < n; i++) {
                if (price <= ask_price.get(i)) {
                    flag = true;
                    if (price == ask_price.get(i)) {
                        ask_size.set(i, size);        
                    }
                    else {
                        ask_price.add(i, price);
                        ask_size.add(i, size);  
                    }
                    if (i==0 && size == 0) {
                        ask_price.remove(0);
                        ask_size.remove(0); 
                    }
                    break;
                }               
            }
            if (flag == false && size > 0) {
                ask_price.add(price);
                ask_size.add(size); 
            }
        }
    }
    
    public int find_size(int price) throws IOException {
        int size;
        int indx;
        size = 0;
        indx = bid_price.indexOf(price);
        if (indx != -1) {
            size = bid_size.get(indx);
        }
        else {
            indx = ask_price.indexOf(price);
            if (indx != -1) {
            size = ask_size.get(indx);
            }
        }
        return size;
    }
    
    public void sell(int size) throws IOException {
        int remain;
        remain = bid_size.get(0) - size;
        if (remain <= 0) {
            bid_size.remove(0);
            bid_price.remove(0);
            int n = bid_size.size();
            while ((n >= 1) && (remain <= 0)) {
                remain = remain + bid_size.get(0);
                if (remain <= 0) {
                   bid_size.remove(0);
                   bid_price.remove(0);
                   n = bid_size.size();
                }
                 else {
                   bid_size.set(0, remain);
                }   
            }
        }
        else {
            bid_size.set(0, remain);
        }       
    }
    
    public void buy(int size) throws IOException {
        int remain;
        remain = ask_size.get(0) - size;
        if (remain <= 0) {
            ask_size.remove(0);
            ask_price.remove(0);
            int n = ask_size.size();
            while ((n >= 1) && (remain <= 0)) {
                remain = remain + ask_size.get(0);
                if (remain <= 0) {
                   ask_size.remove(0);
                   ask_price.remove(0);
                   n = ask_size.size();
                }
                else {
                   ask_size.set(0, remain);
                }   
            }
        }
        else {
            ask_size.set(0, remain);
        }
    }
}
  • Вопрос задан
  • 94 просмотра
Пригласить эксперта
Ответы на вопрос 1
Vest
@Vest
Я не знаю, полезен ли вам будет мой ответ, но я попробую его дать. Я попрофилировал проект в разных программах (Идея и VisualVM) на input.txt файле размером в 86 миллионов строк (просто взял ваш инпут, не разбираясь и наплодил порядка 900мб). Все профайлеры показывают два узких места - это ReadLine и split. Если вам это поможет, вот картинка:
62c16bf2d7077786773526.png
Если попрофилировать память, то она тоже выделяется (и съедается GC), то там две беды (дураки и дороги) byte[] и String.

Я не вникал в задачу целиком, поэтому мой инпут файл конечно же липовый. Но я думаю, если вы сгенерируете что-нибудь большое и рандомное, то я смогу попрофилировать за вас. А пока из решений могу лишь предположить найти какую-нибудь другую альтернативу split для того, чтобы не плодить много мелких объектов.

Кстати, тот сайт предлагает ограничить кучу до 128мб (-Xmx128M), может быть на их примере ваши ArrayList оказываются слишком затратными?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы