Использование StringBuilder для обработки CSV-файлов для экономии места в куче - PullRequest
0 голосов
/ 07 апреля 2010

Я читаю CSV-файл, который имеет около 50 000 строк и 1,1 МБ в размерах (и может увеличиться).

В Code1 я использую String для обработки CSV, в то время как в Code2 я использую StringBuilder (только один поток выполняет код, поэтому нет проблем с параллелизмом)

Использование StringBuilder немного затрудняет чтение кода, используя обычный класс String.

Я преждевременно оптимизирую вещи с помощью StringBuilder в Code2, чтобы сэкономить немного пространства кучи и памяти?

Код1

            fr = new FileReader(file);
            BufferedReader reader = new BufferedReader(fr);

            String line = reader.readLine();
                while ( line != null )
                {
                    int separator = line.indexOf(',');
                    String symbol = line.substring(0, seperator);
                    int begin = separator;
                    separator = line.indexOf(',', begin+1);
                    String price = line.substring(begin+1, seperator);

                    // Publish this update
                    publisher.publishQuote(symbol, price);

                    // Read the next line of fake update data
                    line = reader.readLine();
                 }

Кодекса2

                    fr = new FileReader(file);
                    StringBuilder stringBuilder = new StringBuilder(reader.readLine());

                while( stringBuilder.toString() != null ) {
                    int separator = stringBuilder.toString().indexOf(',');
                    String symbol = stringBuilder.toString().substring(0, separator);
                    int begin = separator;
                    separator = stringBuilder.toString().indexOf(',', begin+1);
                    String price = stringBuilder.toString().substring(begin+1, separator);
                    publisher.publishQuote(symbol, price);

                    stringBuilder.replace(0, stringBuilder.length(), reader.readLine());
                }

Редактировать

Я исключил вызов toString (), поэтому будет меньше создаваемых строковых объектов.

Code3

while( stringBuilder.length() > 0 ) {
                    int separator = stringBuilder.indexOf(",");
                    String symbol = stringBuilder.substring(0, separator);
                    int begin = separator;
                    separator = stringBuilder.indexOf(",", begin+1);
                    String price = stringBuilder.substring(begin+1, separator);
                    publisher.publishQuote(symbol, price);
                    Thread.sleep(10);
                    stringBuilder.replace(0, stringBuilder.length(), reader.readLine());
                }

Кроме того, исходный код загружается с http://www.devx.com/Java/Article/35246/0/page/1

Ответы [ 5 ]

3 голосов
/ 07 апреля 2010

Увеличит ли оптимизированный код производительность приложения? - мой вопрос

Второй пример кода не сохранит вам память и время вычислений.Боюсь, вы могли неправильно понять цель StringBuilder, которая действительно предназначена для построения строк, а не для их чтения.

В цикле или вашем втором примере кода каждая строка содержит выражение stringBuilder.toString()по сути, превращая буферизованную строку в String объект снова и снова.Ваши фактические строковые операции выполняются с этими объектами.Мало того, что первый пример кода проще для чтения, но он, безусловно, также является производительным для двух. - ваш вопрос

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

Чтовид оптимизации может быть сделано для этого кода? - мой вопрос

Если вы профилировали приложение и решили, что это подходящее место для оптимизации, вам следует рассмотреть возможности, предлагаемые Scanner класс.На самом деле, это может как повысить производительность (профилирование покажет, так ли это), так и более простой код.

2 голосов
/ 07 апреля 2010

Я преждевременно оптимизирую вещи с помощью StringBuilder в Code2, чтобы сэкономить немного пространства кучи и памяти?

Скорее всего: да . Но есть только один способ выяснить это: профилировать свой код.

Кроме того, я бы использовал правильный анализатор CSV вместо того, что вы делаете сейчас: http://ostermiller.org/utils/CSV.html

1 голос
/ 07 апреля 2010

Code2 фактически менее эффективен , чем Code1, потому что каждый раз, когда вы вызываете stringBuilder.toString(), вы создаете новый экземпляр java.lang.String (в дополнение к существующему объекту StringBuilder). Это менее эффективно с точки зрения пространства и времени из-за накладных расходов на создание объекта.

Назначение содержимого readLine() непосредственно на String и последующее разделение этого String обычно будет достаточно быстрым. Вы также можете использовать класс Scanner.

Совет по экономии памяти

Если вы встречаете несколько повторяющихся токенов во входных данных, рассмотрите возможность использования String.intern (), чтобы гарантировать, что каждый идентичный токен ссылается на один и тот же объект String; например, * 1 020 *

String[] tokens = parseTokens(line);
for (String token : tokens) {
  // Construct business object referencing interned version of token.
  BusinessObject bo = new BusinessObject(token.intern());
  // Add business object to collection, etc.
}
0 голосов
/ 07 апреля 2010

StringBuilder имеет несколько хороших вещей

  • Операции StringBuffer синхронизированы, а StringBuilder - нет, поэтому использование StringBuilder улучшит производительность в однопоточных сценариях
  • После расширения буфера буфер можетиспользовать повторно, вызывая setLength (0) для объекта.Интересно, что если вы войдете в отладчик и изучите содержимое StringBuilder, вы увидите, что содержимое все еще существует даже после вызова setLength (0).JVM просто сбрасывает указатель на начало строки.В следующий раз, когда вы начнете добавлять символы, указатель будет перемещаться
  • Если вы не совсем уверены в длине строки, лучше использовать StringBuilder, поскольку после расширения буфера вы можете повторно использовать этот же буфер для меньшего или равногоsize

StringBuffer и StringBuilder практически одинаковы во всех операциях, за исключением того, что StringBuffer синхронизирован, а StringBuilder не

Если у вас нет многопоточности, лучше использовать StringBuilder

0 голосов
/ 07 апреля 2010

StringBuilder обычно используется так:

StringBuilder sb = new StringBuilder();
sb.append("You").append(" can chain ")
  .append(" your ").append(" strings ")
  .append("for better readability.");

String myString = sb.toString(); // only call once when you are done
System.out.prinln(sb); // also calls sb.toString().. print myString instead
...