Форматирование Десятичных чисел к строкам для производительности

Можно поместить тесты в tests/ подкаталог приложения (а не tests.py файл) и включать tests/models.py с моделями только для теста.

Затем предоставляют выполняющий тест сценарий ( пример ), который включает Ваш tests/ "приложение" в INSTALLED_APPS. (Это не работает, когда запущенное приложение тестирует из реального проекта, который не будет иметь тестового приложения в INSTALLED_APPS, но я редко нахожу полезным запустить допускающие повторное использование тесты приложения из проекта, и Django 1.6 + не делает по умолчанию.)

( ПРИМЕЧАНИЕ : альтернативный динамический метод описал только ниже работ в Django 1.1 +, если Ваш тестовый сценарий разделяет на подклассы TransactionTestCase - который значительно замедляет Ваши тесты - и больше не работает вообще в Django 1.7 +. Это оставляют здесь только для исторического интереса; не используйте его.)

В начале Ваших тестов (т.е. в методе установки, или в начале ряда doctests), можно динамично добавить "myapp.tests" к установке INSTALLED_APPS и затем сделать это:

from django.core.management import call_command
from django.db.models import loading
loading.cache.loaded = False
call_command('syncdb', verbosity=0)

Затем в конце Ваших тестов, необходимо вымыться путем восстановления старой версии INSTALLED_APPS и очистки кэша приложения снова.

Этот класс инкапсулирует шаблон, таким образом, он не загромождает Ваш тестовый код вполне так же.

5
задан MadMurf 15 September 2009 в 03:48
поделиться

3 ответа

Моя реализация для повышения производительности приведена ниже. Это примерно в 4,5 раза быстрее, чем решение на основе DecimalFormatter: при запуске на моей машине с использованием Eclipse с приличной домашней тестовой системой результаты следующие:

  • По старому методу для выполнения 600 000 вызовов потребовалось 5421 мс (в среднем 0,009035 мс). за звонок)
  • По новому способу на 600 000 вызовов потребовалось 1219 мс (в среднем 0,002032 мс на вызов).

Некоторые примечания:

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

Также: чтобы имитировать поведение оригинала (но не приведенного в комментариях), это:

  • Если во входящем значении дробных цифр больше, чем умещается в масштабе, генерируется ArithmeticException. Если во входящем значении больше целых цифр, чем помещается в (len-scale), возвращаемая строка длиннее, чем len. Если signed имеет значение true, возвращаемая строка будет на единицу длиннее, чем len
    • Однако : если len отрицательное, оригинал возвращает строку с разделителями-запятыми. Это вызывает исключение IllegalARgumentException
    package com.pragmaticsoftwaredevelopment.stackoverflow;
    ...
       final static String formatterZeroes="00000000000000000000000000000000000000000000000000000000000";
       protected static String getFormattedDecimal ( String value, int len, int scale, Boolean signed ) throws IllegalArgumentException {
           if (value.length() == 0) throw new IllegalArgumentException ("Cannot format a zero-length value");
           if (len <= 0) throw new IllegalArgumentException ("Illegal length (" + len + ")");
           StringBuffer retVal = new StringBuffer();
           String sign=null;
           int numStartIdx; 
           if ("+-".indexOf(value.charAt(0)) < 0) {
              numStartIdx=0;
           } else {
              numStartIdx=1;
              if (value.charAt(0) == '-')
                 sign = "-";
           }
           if (signed && (value.charAt(0) != '-'))
              sign = "+";
           if (sign==null)
              sign="";
           retVal.append(sign);
    
    
           int dotIdx = value.indexOf('.');
           int requestedWholePartLength = (len-scale);
    
           if (dotIdx < 0) { 
              int wholePartPadLength = (requestedWholePartLength - ((value.length()-numStartIdx)));
              if (wholePartPadLength > 0)
                 retVal.append(formatterZeroes.substring(0, wholePartPadLength));
              retVal.append (value.substring(numStartIdx));
              if (scale > 0)
                 retVal.append(formatterZeroes.substring(0, scale));
           }
           else {
              int wholePartPadLength = (requestedWholePartLength - (dotIdx - numStartIdx));
              if (wholePartPadLength > 0)
                 retVal.append(formatterZeroes.substring(0, wholePartPadLength));
              retVal.append (value.substring(numStartIdx, dotIdx));
              retVal.append (value.substring (dotIdx+1));
              int fractionalPartPadLength = (scale - (value.length() - 1 - dotIdx));
              if (fractionalPartPadLength > 0)
                 retVal.append(formatterZeroes.substring(0, fractionalPartPadLength));
    
    
           }
    
           return retVal.toString();
       }
    
    8
    ответ дан 18 December 2019 в 13:16
    поделиться

    Если вы для начала получаете ввод в виде String, зачем вам нужно преобразовывать его в BigDecimal и обратно?

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

    4
    ответ дан 18 December 2019 в 13:16
    поделиться

    Я согласен с ChssPly76 в отношении ручных манипуляций со строками.

    Однако, если вы собираетесь перейти по маршруту BigDecimal / DecimalFormat , вы можете рассмотреть возможность совместного использования своих DecimalFormat s вместо создания нового по одному на каждой итерации. Обратите внимание, что эти классы не являются потокобезопасными, поэтому, если вы используете несколько потоков для обработки, вам нужно будет использовать что-то вроде хранилища ThreadLocal для поддержки форматировщика на Thread .

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

    2
    ответ дан 18 December 2019 в 13:16
    поделиться
    Другие вопросы по тегам:

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