Я должен использовать String.format Java (), если производительность важна?

Вы используете [lstm_layer] * num_layers для создания нескольких слоев RNN, которые фактически ссылаются на один и тот же объект в python. Это использование является нормальным в некоторых версиях tenorflow, а некоторые версии сообщают об ошибках.

Как говорится в предупреждении, поскольку все уровни RNN являются одним и тем же объектом, их весовые коэффициенты будут оставаться одинаковыми. Все ошибки возвращаются на уровень RNN. Это эквивалентно уменьшению параметров модели и уменьшению сложности модели.

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

rnn_layers = []
for _ in range(num_layers):
    lstm_layer = rnn.LSTMBlockCell(num_units, forget_bias=1)
    lstm_layer = rnn.DropoutWrapper(lstm_layer, output_keep_prob=output_keep_prob)
    rnn_layers.append(lstm_layer)

stacked_lstm = rnn.MultiRNNCell(rnn_layers)
207
задан pasignature 3 April 2019 в 03:05
поделиться

7 ответов

Я записал маленький класс для тестирования, который имеет лучшую производительность двух, и + прибывает перед форматом. фактором 5 - 6. Попробуйте его Ваш сам

import java.io.*;
import java.util.Date;

public class StringTest{

    public static void main( String[] args ){
    int i = 0;
    long prev_time = System.currentTimeMillis();
    long time;

    for( i = 0; i< 100000; i++){
        String s = "Blah" + i + "Blah";
    }
    time = System.currentTimeMillis() - prev_time;

    System.out.println("Time after for loop " + time);

    prev_time = System.currentTimeMillis();
    for( i = 0; i<100000; i++){
        String s = String.format("Blah %d Blah", i);
    }
    time = System.currentTimeMillis() - prev_time;
    System.out.println("Time after for loop " + time);

    }
}

, Рабочее вышеупомянутое для другого N показывает, что оба ведут себя линейно, но String.format в 5-30 раз медленнее.

причина состоит в том, что в текущей реализации String.format первые синтаксические анализы вход с регулярными выражениями и затем заполняет параметры. Конкатенация с плюс, с другой стороны, оптимизирована javac (не JIT) и использует StringBuilder.append непосредственно.

Runtime comparison

120
ответ дан kritzikratzi 23 November 2019 в 04:44
поделиться

Ответ на это зависит очень от того, как Ваш определенный компилятор Java оптимизирует байт-код, который он генерирует. Строки неизменны и, теоретически, каждый "+", операция может создать новый. Но, Ваш компилятор почти наверняка оптимизирует далеко временные шаги в создании длинных строк. Совершенно возможно, что обе строки кода выше генерируют тот же самый байт-код.

единственный реальный способ знать состоит в том, чтобы протестировать код многократно в Вашей текущей среде. Запишите приложение QD, которое связывает строки оба пути многократно, и посмотрите, как они испытывают таймаут друг против друга.

0
ответ дан Yes - that Jake. 23 November 2019 в 04:44
поделиться

Я просто изменил тест hhafez для включения StringBuilder. StringBuilder в 33 раза быстрее, чем String.format, использующий jdk 1.6.0_10 клиент на XP. Используя - переключатель сервера понижает фактор к 20.

public class StringTest {

   public static void main( String[] args ) {
      test();
      test();
   }

   private static void test() {
      int i = 0;
      long prev_time = System.currentTimeMillis();
      long time;

      for ( i = 0; i < 1000000; i++ ) {
         String s = "Blah" + i + "Blah";
      }
      time = System.currentTimeMillis() - prev_time;

      System.out.println("Time after for loop " + time);

      prev_time = System.currentTimeMillis();
      for ( i = 0; i < 1000000; i++ ) {
         String s = String.format("Blah %d Blah", i);
      }
      time = System.currentTimeMillis() - prev_time;
      System.out.println("Time after for loop " + time);

      prev_time = System.currentTimeMillis();
      for ( i = 0; i < 1000000; i++ ) {
         new StringBuilder("Blah").append(i).append("Blah");
      }
      time = System.currentTimeMillis() - prev_time;
      System.out.println("Time after for loop " + time);
   }
}

, В то время как это могло бы звучать решительным, я полагаю, что это релевантно только в редких случаях, потому что абсолютные числа являются довольно небольшими: 4 с для 1 миллиона простых вызовов String.format являются видом хорошо - пока я использую их для входа и т.п.

Обновление: , Как указано sjbotha в комментариях, тест StringBuilder недопустим, так как он пропускает финал .toString().

корректный фактор ускорения от String.format(.) до StringBuilder 23 на моей машине (16 с эти -server переключатель).

2
ответ дан the.duckman 23 November 2019 в 04:44
поделиться

Обычно необходимо использовать Строку. Формат, потому что это относительно быстро и это поддерживает глобализацию (предполагающий, что Вы на самом деле пытаетесь записать что-то, что читается пользователем). Это также помогает объединиться, при попытке перевести одну строку по сравнению с 3 или больше на оператор (специально для языков, которые имеют решительно различные грамматические структуры).

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

5
ответ дан Orion Adrian 23 November 2019 в 04:44
поделиться

Для расширений/исправления на первом ответе выше это не перевод, которому String.format помог бы с на самом деле.
то, С чем поможет String.format, - когда Вы печатаете дату/время (или числовой формат, и т.д.), где существует локализация (l10n) различия (т.е., некоторые страны распечатают 04Feb2009, и другие распечатают Feb042009).
С переводом, Вы просто говорите о перемещении любых externalizable строк (как сообщения об ошибках и этажерка) в пакет свойства так, чтобы можно было использовать правильный пакет для правильного языка, с помощью ResourceBundle и MessageFormat.

Рассмотрение всего вышеупомянутого, я сказал бы, что мудрый производительностью, String.format по сравнению с простой конкатенацией сводится к тому, что Вы предпочитаете. Если Вы предпочитаете смотреть на вызовы к .format по конкатенации, то любой ценой, пойдите с этим.
, В конце концов, код прочитан намного больше, чем он записан.

8
ответ дан dw.mackie 23 November 2019 в 04:44
поделиться

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

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

кроме того, что-то еще необходимо знать: остерегайтесь использования подстроки (). Например:

String getSmallString() {
  String largeString = // load from file; say 2M in size
  return largeString.substring(100, 300);
}

, Что большая строка находится все еще в памяти, потому что это, как работают подстроки Java. Лучшая версия:

  return new String(largeString.substring(100, 300));

или

  return String.format("%s", largeString.substring(100, 300));

вторая форма, вероятно, более полезна при выполнении другого материала одновременно.

6
ответ дан ErikE 23 November 2019 в 04:44
поделиться

Я взял код hhafez и добавил тест памяти :

private static void test() {
    Runtime runtime = Runtime.getRuntime();
    long memory;
    ...
    memory = runtime.freeMemory();
    // for loop code
    memory = memory-runtime.freeMemory();

Я запускаю его отдельно для каждого подхода, оператор '+', String .format и StringBuilder (вызов toString ()), поэтому другие подходы не повлияют на используемую память. Я добавил больше конкатенаций, сделав строку как «Blah» + i + «Blah» + i + «Blah» + i + «Blah».

Результат следующий (в среднем по 5 запусков каждая):
Время подхода (мс) Выделенная память (длинная)
Оператор "+" 747 320 504
String.format 16484 373,312
StringBuilder 769 57,344

Мы видим, что String '+' и StringBuilder практически идентичны по времени, но StringBuilder намного эффективнее использует память. Это очень важно, когда у нас есть много вызовов журнала (или любых других операторов, связанных со строками) за достаточно короткий промежуток времени, чтобы сборщик мусора не мог очистить множество экземпляров строк, являющихся результатом оператора '+'.

И примечание, кстати, не забудьте проверить уровень ведения журнала перед построением сообщения.

Выводы:

  1. Я продолжу использовать StringBuilder.
  2. У меня слишком много времени или слишком мало жизни.
238
ответ дан 23 November 2019 в 04:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: