Использование скорости Apache с StringBuilders / CharSequence - PullRequest
1 голос
/ 07 марта 2011

Мы используем Apache Velocity для динамических шаблонов. На данный момент Velocity имеет следующие методы оценки / замены:

public static boolean evaluate(Context context, Writer writer, String logTag, Reader reader)

public static boolean evaluate(Context context, Writer out, String logTag, String instring)

Мы используем эти методы, предоставляя StringWriter для записи результатов оценки. Наши входящие данные поступают в формате StringBuilder, поэтому мы используем StringBuilder.toString и передаем их как instring.

Проблема в том, что наши шаблоны довольно велики (в редких случаях они могут быть мегабайтами, десятками мс), замены происходят очень часто, и каждая операция замены утраивает объем необходимой памяти (входящие данные + StringBuilder.toString(), которая создает новую копию + исходящие данные).

Мне было интересно, есть ли способ улучшить это. Например. если бы я мог найти способ предоставить Reader и Writer поверх того же экземпляра StringBuilder, который использует только дополнительную память для различий ввода / вывода, это был бы хороший подход? Кто-нибудь делал что-нибудь подобное и мог бы поделиться источником для такого класса? Или, может быть, есть более эффективные решения данной проблемы?

Ответы [ 3 ]

2 голосов
/ 13 марта 2011

Скорость должна проанализировать весь шаблон, прежде чем его можно будет оценить. Вы не сможете предоставить Reader и Writer, чтобы получить что-либо за одну оценку. Однако вы можете разбить ваши шаблоны на более мелкие части, чтобы оценить их по отдельности. Это будет зависеть от того, что в них, и если части будут зависеть друг от друга. И накладные расходы могут не стоить того, в зависимости от вашей ситуации.

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

Если есть директивы #set, вам нужно будет передавать один и тот же контекст для оценки. Если есть какие-либо блоки #if или #foreach, это будет сложно. На самом деле я делал это раньше и читал достаточно строк, чтобы захватить блок ввода, чтобы Velocity могла его проанализировать и оценить. Однако в этот момент вы начинаете выполнять работу Velocity, и, вероятно, это того не стоит.

1 голос
/ 17 марта 2011

Вы можете сохранить одну копию строки, прочитав поле value из StringBuilder через отражение и создав CharArrayReader для этого:

    StringBuilder sb = new StringBuilder("bla");
    Field valueField = StringBuilder.class.getSuperclass().getDeclaredField("value");
    valueField.setAccessible(true);
    char[] value = (char[]) valueField.get(sb);
    Reader r = new CharArrayReader(value, 0, sb.length());
0 голосов
/ 07 марта 2011

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

Я не слышал ни о каком решении, которое бы соответствовало этому, но так как Reader не является особенно сложным классом, мой инстинкт был бы просто создать свой собственный класс StringBufferReader и передать его.

...